diff --git a/Dorkbox-Util/src/dorkbox/util/crypto/Crypto.java b/Dorkbox-Util/src/dorkbox/util/crypto/Crypto.java index d017653..be18882 100644 --- a/Dorkbox-Util/src/dorkbox/util/crypto/Crypto.java +++ b/Dorkbox-Util/src/dorkbox/util/crypto/Crypto.java @@ -16,61 +16,20 @@ package dorkbox.util.crypto; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.Security; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.PBEParametersGenerator; +import dorkbox.util.OS; +import dorkbox.util.bytes.LittleEndian; +import org.bouncycastle.crypto.*; import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.engines.IESEngine; -import org.bouncycastle.crypto.generators.DSAKeyPairGenerator; -import org.bouncycastle.crypto.generators.DSAParametersGenerator; -import org.bouncycastle.crypto.generators.ECKeyPairGenerator; -import org.bouncycastle.crypto.generators.KDF2BytesGenerator; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import org.bouncycastle.crypto.generators.*; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.crypto.params.DSAKeyGenerationParameters; -import org.bouncycastle.crypto.params.DSAParameters; -import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; -import org.bouncycastle.crypto.params.DSAPublicKeyParameters; -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.crypto.params.ECKeyGenerationParameters; -import org.bouncycastle.crypto.params.ECPrivateKeyParameters; -import org.bouncycastle.crypto.params.ECPublicKeyParameters; -import org.bouncycastle.crypto.params.IESParameters; -import org.bouncycastle.crypto.params.IESWithCipherParameters; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; -import org.bouncycastle.crypto.params.RSAKeyParameters; -import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.bouncycastle.crypto.params.*; import org.bouncycastle.crypto.signers.DSASigner; import org.bouncycastle.crypto.signers.ECDSASigner; import org.bouncycastle.crypto.signers.PSSSigner; @@ -81,37 +40,51 @@ import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.math.ec.ECFieldElement; import org.bouncycastle.math.ec.ECPoint; -import dorkbox.util.OS; -import dorkbox.util.bytes.LittleEndian; +import java.io.*; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; /** * http://en.wikipedia.org/wiki/NSA_Suite_B * http://www.nsa.gov/ia/programs/suiteb_cryptography/ - * + *

* NSA Suite B - * + *

* TOP-SECRET LEVEL * AES256/GCM * ECC with 384-bit prime curve (FIPS PUB 186-3), and SHA-384 - * + *

* SECRET LEVEL * AES 128 * ECDH and ECDSA using the 256-bit prime (FIPS PUB 186-3), and SHA-256. RSA with 2048 can be used for DH key negotiation - * + *

* WARNING! * Note that this call is INCOMPATIBLE with GWT, so we have EXCLUDED IT from gwt, and created a CryptoGwt class in the web-client project * which only has the necessary crypto utility methods that are - * 1) Necessary - * 2) Compatible with GWT - * - * - * To determine if we have hardware acclerated AES + * 1) Necessary + * 2) Compatible with GWT + *

+ *

+ * To determine if we have hardware accelerated AES * java -XX:+PrintFlagsFinal -version | grep UseAES */ -public class Crypto { +public final +class Crypto { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Crypto.class); - public static final void addProvider() { + private + Crypto() { + } + + public static + void addProvider() { // make sure we only add it once (in case it's added elsewhere...) Provider provider = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME); if (provider == null) { @@ -119,19 +92,34 @@ public class Crypto { } } - public static class Util { + public static final + class Util { + + private + Util() { + } /** * Return the hash of the file or NULL if file is invalid */ - public static final byte[] hashFile(File file, Digest digest) { + public static + byte[] hashFile(File file, Digest digest) { return hashFile(file, digest, 0L); } /** * Return the hash of the file or NULL if file is invalid */ - public static final byte[] hashFile(File file, Digest digest, long lengthFromEnd) { + public static + byte[] hashFile(File file, Digest digest, long lengthFromEnd) { + return hashFile(file, digest, lengthFromEnd, null); + } + + /** + * Return the hash of the file or NULL if the file is invalid. ALSO includes the hash of the 'extraData' if specified. + */ + public static + byte[] hashFile(File file, Digest digest, long lengthFromEnd, byte[] extraData) { if (file.isFile() && file.canRead()) { InputStream inputStream = null; try { @@ -172,22 +160,29 @@ public class Crypto { } } + if (extraData != null) { + digest.update(extraData, 0, extraData.length); + } + byte[] digestBytes = new byte[digest.getDigestSize()]; digest.doFinal(digestBytes, 0); return digestBytes; - } else { + } + else { return null; } } // CUSTOM_HEADER USE - private static byte[] CUSTOM_HEADER = new byte[] {-2, -54, -54, -98}; + private static final byte[] CUSTOM_HEADER = new byte[] {-2, -54, -54, -98}; + /** * Specifically, to return the hash of the ALL files/directories inside the jar, minus the action specified (LGPL) files. */ - public static final byte[] hashJarContentsExcludeAction(File jarDestFilename, Digest digest, int action) throws IOException { + public static + byte[] hashJarContentsExcludeAction(File jarDestFilename, Digest digest, int action) throws IOException { JarFile jarDestFile = new JarFile(jarDestFilename); try { @@ -217,7 +212,8 @@ public class Crypto { byte[] extraData = jarEntry.getExtra(); if (extraData == null || extraData.length == 0) { okToHash = false; - } else if (extraData.length >= 4) { + } + else if (extraData.length >= 4) { for (int i = 0; i < CUSTOM_HEADER.length; i++) { if (extraData[i] != CUSTOM_HEADER[i]) { throw new RuntimeException("Unexpected extra data in zip assigned. Aborting"); @@ -234,10 +230,12 @@ public class Crypto { if ((fileAction & action) != action) { okToHash = true; } - } else { + } + else { okToHash = true; } - } else { + } + else { throw new RuntimeException("Unexpected extra data in zip assigned. Aborting"); } @@ -260,9 +258,10 @@ public class Crypto { digest.update(buffer, 0, read); } inputStream.close(); - } else { -// System.err.println("Skipping: " + name); } + //else { + // System.err.println("Skipping: " + name); + //} } } catch (Exception e) { throw new RuntimeException("Unexpected extra data in zip assigned. Aborting"); @@ -279,7 +278,8 @@ public class Crypto { /** * Hash an input stream, based on the specified digest */ - public static byte[] hashStream(Digest digest, InputStream inputStream) throws IOException { + public static + byte[] hashStream(Digest digest, InputStream inputStream) throws IOException { byte[] buffer = new byte[2048]; int read = 0; @@ -300,12 +300,13 @@ public class Crypto { /** * Secure way to generate an AES key based on a password. Will '*' out the passed-in password * - * @param password will be filled with '*' - * @param salt should be a RANDOM number, at least 256bits (32 bytes) in size. + * @param password will be filled with '*' + * @param salt should be a RANDOM number, at least 256bits (32 bytes) in size. * @param iterationCount should be a lot, like 10,000 * @return the secure key to use */ - public static final byte[] PBKDF2(char[] password, byte[] salt, int iterationCount) { + public static + byte[] PBKDF2(char[] password, byte[] salt, int iterationCount) { // will also zero out the password. byte[] charToBytes = Crypto.Util.charToBytesPassword(password); @@ -315,12 +316,13 @@ public class Crypto { /** * Secure way to generate an AES key based on a password. * - * @param password - * @param salt should be a RANDOM number, at least 256bits (32 bytes) in size. + * @param password The password that you want to mix + * @param salt should be a RANDOM number, at least 256bits (32 bytes) in size. * @param iterationCount should be a lot, like 10,000 * @return the secure key to use */ - public static final byte[] PBKDF2(byte[] password, byte[] salt, int iterationCount) { + public static + byte[] PBKDF2(byte[] password, byte[] salt, int iterationCount) { SHA256Digest digest = new SHA256Digest(); PBEParametersGenerator pGen = new PKCS5S2ParametersGenerator(digest); pGen.init(password, salt, iterationCount); @@ -328,19 +330,22 @@ public class Crypto { KeyParameter key = (KeyParameter) pGen.generateDerivedMacParameters(digest.getDigestSize() * 8); // *8 for bit length. // zero out the password. - Arrays.fill(password, (byte)0); + Arrays.fill(password, (byte) 0); return key.getKey(); } - /** this saves the char array in UTF-16 format of bytes and BLANKS out the password char array. */ - public static final byte[] charToBytesPassword(char[] password) { + /** + * this saves the char array in UTF-16 format of bytes and BLANKS out the password char array. + */ + public static + byte[] charToBytesPassword(char[] password) { // note: this saves the char array in UTF-16 format of bytes. - byte[] passwordBytes = new byte[password.length*2]; - for(int i=0; i>8); - passwordBytes[2*i+1] = (byte) (password[i] & 0x00FF); + byte[] passwordBytes = new byte[password.length * 2]; + for (int i = 0; i < password.length; i++) { + passwordBytes[2 * i] = (byte) ((password[i] & 0xFF00) >> 8); + passwordBytes[2 * i + 1] = (byte) (password[i] & 0x00FF); } // asterisk out the password @@ -351,20 +356,26 @@ public class Crypto { } - public static class AES { + public static final + class AES { private static final int ivSize = 16; + private + AES() { + } + /** * AES encrypts data with a specified key. * * @return empty byte[] if error */ - public static final byte[] encryptWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { + public static + byte[] encryptWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { byte[] encryptAES = encrypt(aesEngine, aesKey, aesIV, data); int length = encryptAES.length; - byte[] out = new byte[length+ivSize]; + byte[] out = new byte[length + ivSize]; System.arraycopy(aesIV, 0, out, 0, ivSize); System.arraycopy(encryptAES, 0, out, ivSize, length); @@ -373,21 +384,22 @@ public class Crypto { /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES encrypts data with a specified key. * * @return empty byte[] if error */ @Deprecated - public static final byte[] encryptWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { + public static + byte[] encryptWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { byte[] encryptAES = encrypt(aesEngine, aesKey, aesIV, data); int length = encryptAES.length; - byte[] out = new byte[length+ivSize]; + byte[] out = new byte[length + ivSize]; System.arraycopy(aesIV, 0, out, 0, ivSize); System.arraycopy(encryptAES, 0, out, ivSize, length); @@ -399,8 +411,8 @@ public class Crypto { * * @return true if successful */ - public static final boolean encryptStreamWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, - InputStream in, OutputStream out) { + public static + boolean encryptStreamWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out) { try { out.write(aesIV); @@ -409,22 +421,21 @@ public class Crypto { return false; } - boolean success = encryptStream(aesEngine, aesKey, aesIV, in, out); - return success; + return encryptStream(aesEngine, aesKey, aesIV, in, out); } /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES encrypts data with a specified key. * * @return true if successful */ @Deprecated - public static final boolean encryptStreamWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, - InputStream in, OutputStream out) { + public static + boolean encryptStreamWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out) { try { out.write(aesIV); @@ -433,8 +444,7 @@ public class Crypto { return false; } - boolean success = encryptStream(aesEngine, aesKey, aesIV, in, out); - return success; + return encryptStream(aesEngine, aesKey, aesIV, in, out); } @@ -443,7 +453,8 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] encrypt(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { + public static + byte[] encrypt(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { int length = data.length; CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV); @@ -469,7 +480,8 @@ public class Crypto { if (outBuf.length == actualLength) { return outBuf; - } else { + } + else { byte[] result = new byte[actualLength]; System.arraycopy(outBuf, 0, result, 0, result.length); return result; @@ -482,8 +494,9 @@ public class Crypto { * * @return length of encrypted data, -1 if there was an error. */ - public static final int encrypt(dorkbox.util.crypto.bouncycastle.GCMBlockCipher_ByteBuf aesEngine, CipherParameters aesIVAndKey, - io.netty.buffer.ByteBuf inBuffer, io.netty.buffer.ByteBuf outBuffer, int length) { + public static + int encrypt(dorkbox.util.crypto.bouncycastle.GCMBlockCipher_ByteBuf aesEngine, CipherParameters aesIVAndKey, + io.netty.buffer.ByteBuf inBuffer, io.netty.buffer.ByteBuf outBuffer, int length) { aesEngine.reset(); aesEngine.init(true, aesIVAndKey); @@ -514,15 +527,16 @@ public class Crypto { /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES encrypts data with a specified key. * * @return empty byte[] if error */ @Deprecated - public static final byte[] encrypt(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { + public static + byte[] encrypt(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { int length = data.length; CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV); @@ -548,7 +562,8 @@ public class Crypto { if (outBuf.length == actualLength) { return outBuf; - } else { + } + else { byte[] result = new byte[actualLength]; System.arraycopy(outBuf, 0, result, 0, result.length); return result; @@ -557,16 +572,16 @@ public class Crypto { /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES encrypt from one stream to another. * * @return true if successful */ @Deprecated - public static final boolean encryptStream(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, - InputStream in, OutputStream out) { + public static + boolean encryptStream(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out) { byte[] buf = new byte[ivSize]; byte[] outbuf = new byte[512]; @@ -608,8 +623,8 @@ public class Crypto { * * @return true if successful */ - public static final boolean encryptStream(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, - InputStream in, OutputStream out) { + public static + boolean encryptStream(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out) { byte[] buf = new byte[ivSize]; byte[] outbuf = new byte[512]; @@ -652,11 +667,12 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] decryptWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] data) { + public static + byte[] decryptWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] data) { byte[] aesIV = new byte[ivSize]; System.arraycopy(data, 0, aesIV, 0, ivSize); - byte[] in = new byte[data.length-ivSize]; + byte[] in = new byte[data.length - ivSize]; System.arraycopy(data, ivSize, in, 0, in.length); return decrypt(aesEngine, aesKey, aesIV, in); @@ -664,19 +680,20 @@ public class Crypto { /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES decrypt (if the aes IV is included in the data) * * @return empty byte[] if error */ @Deprecated - public static final byte[] decryptWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] data) { + public static + byte[] decryptWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] data) { byte[] aesIV = new byte[ivSize]; System.arraycopy(data, 0, aesIV, 0, ivSize); - byte[] in = new byte[data.length-ivSize]; + byte[] in = new byte[data.length - ivSize]; System.arraycopy(data, ivSize, in, 0, in.length); return decrypt(aesEngine, aesKey, aesIV, in); @@ -687,8 +704,8 @@ public class Crypto { * * @return true if successful */ - public static final boolean decryptStreamWithIV(GCMBlockCipher aesEngine, byte[] aesKey, - InputStream in, OutputStream out) { + public static + boolean decryptStreamWithIV(GCMBlockCipher aesEngine, byte[] aesKey, InputStream in, OutputStream out) { byte[] aesIV = new byte[ivSize]; try { in.read(aesIV, 0, ivSize); @@ -697,22 +714,21 @@ public class Crypto { return false; } - boolean success = decryptStream(aesEngine, aesKey, aesIV, in, out); - return success; + return decryptStream(aesEngine, aesKey, aesIV, in, out); } /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES decrypt (if the aes IV is included in the data) * * @return true if successful */ @Deprecated - public static final boolean decryptStreamWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, - InputStream in, OutputStream out) { + public static + boolean decryptStreamWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, InputStream in, OutputStream out) { byte[] aesIV = new byte[ivSize]; try { in.read(aesIV, 0, ivSize); @@ -721,8 +737,7 @@ public class Crypto { return false; } - boolean success = decryptStream(aesEngine, aesKey, aesIV, in, out); - return success; + return decryptStream(aesEngine, aesKey, aesIV, in, out); } /** @@ -730,7 +745,8 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] decrypt(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { + public static + byte[] decrypt(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { int length = data.length; CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV); @@ -756,7 +772,8 @@ public class Crypto { if (outBuf.length == actualLength) { return outBuf; - } else { + } + else { byte[] result = new byte[actualLength]; System.arraycopy(outBuf, 0, result, 0, result.length); return result; @@ -768,8 +785,9 @@ public class Crypto { * * @return length of decrypted data, -1 if there was an error. */ - public static final int decrypt(dorkbox.util.crypto.bouncycastle.GCMBlockCipher_ByteBuf aesEngine, ParametersWithIV aesIVAndKey, - io.netty.buffer.ByteBuf bufferWithData, io.netty.buffer.ByteBuf bufferTempData, int length) { + public static + int decrypt(dorkbox.util.crypto.bouncycastle.GCMBlockCipher_ByteBuf aesEngine, ParametersWithIV aesIVAndKey, + io.netty.buffer.ByteBuf bufferWithData, io.netty.buffer.ByteBuf bufferTempData, int length) { aesEngine.reset(); aesEngine.init(false, aesIVAndKey); @@ -799,15 +817,16 @@ public class Crypto { /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES decrypt (if we already know the aes IV -- and it's NOT included in the data) * * @return empty byte[] if error */ @Deprecated - public static final byte[] decrypt(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { + public static + byte[] decrypt(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data) { int length = data.length; @@ -834,7 +853,8 @@ public class Crypto { if (outBuf.length == actualLength) { return outBuf; - } else { + } + else { byte[] result = new byte[actualLength]; System.arraycopy(outBuf, 0, result, 0, result.length); return result; @@ -846,8 +866,8 @@ public class Crypto { * * @return true if successful */ - public static final boolean decryptStream(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, - InputStream in, OutputStream out) { + public static + boolean decryptStream(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out) { byte[] buf = new byte[ivSize]; byte[] outbuf = new byte[512]; @@ -886,16 +906,16 @@ public class Crypto { /** * CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO - *

+ *

* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted data. - *

+ *

* AES decrypt from one stream to another. * * @return true if successful */ @Deprecated - public static final boolean decryptStream(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, - InputStream in, OutputStream out) { + public static + boolean decryptStream(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out) { byte[] buf = new byte[ivSize]; byte[] outbuf = new byte[512]; @@ -935,13 +955,17 @@ public class Crypto { - - // Note: this is here just for keeping track of how this is done. This should NOT be used, and instead use ECC crypto. @Deprecated - public static class RSA { + public static final + class RSA { - public static final AsymmetricCipherKeyPair generateKeyPair(SecureRandom secureRandom, int keyLength) { + private + RSA() { + } + + public static + AsymmetricCipherKeyPair generateKeyPair(SecureRandom secureRandom, int keyLength) { RSAKeyPairGenerator keyGen = new RSAKeyPairGenerator(); RSAKeyGenerationParameters params = new RSAKeyGenerationParameters(new BigInteger("65537"), // public exponent secureRandom, //pnrg @@ -954,15 +978,15 @@ public class Crypto { /** * RSA encrypt using public key A, and sign data with private key B. - * + *

* byte[0][] = encrypted data * byte[1][] = signature * * @return empty byte[][] if error */ - public static final byte[][] encryptAndSign(AsymmetricBlockCipher rsaEngine, Digest digest, - RSAKeyParameters rsaPublicKeyA, RSAPrivateCrtKeyParameters rsaPrivateKeyB, - byte[] bytes) { + public static + byte[][] encryptAndSign(AsymmetricBlockCipher rsaEngine, Digest digest, RSAKeyParameters rsaPublicKeyA, + RSAPrivateCrtKeyParameters rsaPrivateKeyB, byte[] bytes) { if (bytes.length == 0) { return new byte[0][0]; } @@ -995,9 +1019,9 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] decryptAndVerify(AsymmetricBlockCipher rsaEngine, Digest digest, - RSAKeyParameters rsaPublicKeyA, RSAPrivateCrtKeyParameters rsaPrivateKeyB, - byte[] encryptedData, byte[] signature) { + public static + byte[] decryptAndVerify(AsymmetricBlockCipher rsaEngine, Digest digest, RSAKeyParameters rsaPublicKeyA, + RSAPrivateCrtKeyParameters rsaPrivateKeyB, byte[] encryptedData, byte[] signature) { if (encryptedData.length == 0 || signature.length == 0) { return new byte[0]; } @@ -1010,9 +1034,7 @@ public class Crypto { return new byte[0]; } - byte[] decryptBytes = decrypt(rsaEngine, rsaPrivateKeyB, encryptedData); - - return decryptBytes; + return decrypt(rsaEngine, rsaPrivateKeyB, encryptedData); } @@ -1021,14 +1043,15 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] encrypt(AsymmetricBlockCipher rsaEngine, RSAKeyParameters rsaPublicKey, byte[] bytes) { + public static + byte[] encrypt(AsymmetricBlockCipher rsaEngine, RSAKeyParameters rsaPublicKey, byte[] bytes) { rsaEngine.init(true, rsaPublicKey); try { int inputBlockSize = rsaEngine.getInputBlockSize(); if (inputBlockSize < bytes.length) { int outSize = rsaEngine.getOutputBlockSize(); - int realsize = (int) Math.round(bytes.length/(outSize*1.0D)+.5); + int realsize = (int) Math.round(bytes.length / (outSize * 1.0D) + .5); ByteBuffer buffer = ByteBuffer.allocateDirect(outSize * realsize); int position = 0; @@ -1045,7 +1068,8 @@ public class Crypto { return buffer.array(); - } else { + } + else { return rsaEngine.processBlock(bytes, 0, bytes.length); } } catch (InvalidCipherTextException e) { @@ -1059,14 +1083,15 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] decrypt(AsymmetricBlockCipher rsaEngine, RSAPrivateCrtKeyParameters rsaPrivateKey, byte[] bytes) { + public static + byte[] decrypt(AsymmetricBlockCipher rsaEngine, RSAPrivateCrtKeyParameters rsaPrivateKey, byte[] bytes) { rsaEngine.init(false, rsaPrivateKey); try { int inputBlockSize = rsaEngine.getInputBlockSize(); if (inputBlockSize < bytes.length) { int outSize = rsaEngine.getOutputBlockSize(); - int realsize = (int) Math.round(bytes.length/(outSize*1.0D)+.5); + int realsize = (int) Math.round(bytes.length / (outSize * 1.0D) + .5); ByteArrayOutputStream buffer = new ByteArrayOutputStream(outSize * realsize); int position = 0; @@ -1082,7 +1107,8 @@ public class Crypto { return buffer.toByteArray(); - } else { + } + else { return rsaEngine.processBlock(bytes, 0, bytes.length); } } catch (InvalidCipherTextException e) { @@ -1096,7 +1122,8 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] sign(PSSSigner signer, RSAPrivateCrtKeyParameters rsaPrivateKey, byte[] mesg) { + public static + byte[] sign(PSSSigner signer, RSAPrivateCrtKeyParameters rsaPrivateKey, byte[] mesg) { signer.init(true, rsaPrivateKey); signer.update(mesg, 0, mesg.length); @@ -1111,14 +1138,16 @@ public class Crypto { /** * RSA verify data with a specified key. */ - public static final boolean verify(PSSSigner signer, RSAKeyParameters rsaPublicKey, byte[] sig, byte[] mesg) { + public static + boolean verify(PSSSigner signer, RSAKeyParameters rsaPublicKey, byte[] sig, byte[] mesg) { signer.init(false, rsaPublicKey); signer.update(mesg, 0, mesg.length); return signer.verifySignature(sig); } - public static boolean compare(RSAKeyParameters publicA, RSAKeyParameters publicB) { + public static + boolean compare(RSAKeyParameters publicA, RSAKeyParameters publicB) { if (!publicA.getExponent().equals(publicB.getExponent())) { return false; } @@ -1129,7 +1158,8 @@ public class Crypto { return true; } - public static boolean compare(RSAPrivateCrtKeyParameters private1, RSAPrivateCrtKeyParameters private2) { + public static + boolean compare(RSAPrivateCrtKeyParameters private1, RSAPrivateCrtKeyParameters private2) { if (!private1.getModulus().equals(private2.getModulus())) { return false; } @@ -1161,36 +1191,41 @@ public class Crypto { - // Note: this is here just for keeping track of how this is done. This should NOT be used, and instead use ECC crypto. @Deprecated - public static class DSA { + public static final + class DSA { + private + DSA() { + } + /** * Generates the DSA key (using RSA and SHA1) - *

+ *

* Note: this is here just for keeping track of how this is done. This should NOT be used, and instead use ECC crypto. */ - public static final AsymmetricCipherKeyPair generateKeyPair(SecureRandom secureRandom, int keyLength) { + public static + AsymmetricCipherKeyPair generateKeyPair(SecureRandom secureRandom, int keyLength) { DSAKeyPairGenerator keyGen = new DSAKeyPairGenerator(); DSAParametersGenerator dsaParametersGenerator = new DSAParametersGenerator(); dsaParametersGenerator.init(keyLength, 20, secureRandom); DSAParameters generateParameters = dsaParametersGenerator.generateParameters(); - DSAKeyGenerationParameters params = new DSAKeyGenerationParameters(secureRandom, - generateParameters); + DSAKeyGenerationParameters params = new DSAKeyGenerationParameters(secureRandom, generateParameters); keyGen.init(params); return keyGen.generateKeyPair(); } /** * The message will have the SHA1 hash calculated and used for the signature. - *

+ *

* Note: this is here just for keeping track of how this is done. This should NOT be used, and instead use ECC crypto. - * + *

* The returned signature is the {r,s} signature array. */ - public static final BigInteger[] generateSignature(DSAPrivateKeyParameters privateKey, SecureRandom secureRandom, byte[] message) { + public static + BigInteger[] generateSignature(DSAPrivateKeyParameters privateKey, SecureRandom secureRandom, byte[] message) { ParametersWithRandom param = new ParametersWithRandom(privateKey, secureRandom); DSASigner dsa = new DSASigner(); @@ -1211,13 +1246,14 @@ public class Crypto { /** * The message will have the SHA1 hash calculated and used for the signature. - *

+ *

* Note: this is here just for keeping track of how this is done. This should NOT be used, and instead use ECC crypto. * * @param signature is the {r,s} signature array. * @return true if the signature is valid */ - public static final boolean verifySignature(DSAPublicKeyParameters publicKey, byte[] message, BigInteger[] signature) { + public static + boolean verifySignature(DSAPublicKeyParameters publicKey, byte[] message, BigInteger[] signature) { SHA1Digest sha1Digest = new SHA1Digest(); byte[] checksum = new byte[sha1Digest.getDigestSize()]; @@ -1229,14 +1265,14 @@ public class Crypto { dsa.init(false, publicKey); - boolean verifySignature = dsa.verifySignature(checksum, signature[0], signature[1]); - return verifySignature; + return dsa.verifySignature(checksum, signature[0], signature[1]); } } - public static class ECC { + public static final + class ECC { static final String ECC_NAME = "EC"; public static final String p521_curve = "secp521r1"; @@ -1250,35 +1286,38 @@ public class Crypto { public static final int macSize = 512; - /** - * Uses SHA512 - */ - public static final IESEngine createEngine() { - return new IESEngine(new ECDHCBasicAgreement(), - new KDF2BytesGenerator(new SHA384Digest()), - new HMac(new SHA512Digest())); + private + ECC() { } /** * Uses SHA512 */ - public static final IESEngine createEngine(PaddedBufferedBlockCipher aesEngine) { - return new IESEngine(new ECDHCBasicAgreement(), - new KDF2BytesGenerator(new SHA384Digest()), - new HMac(new SHA512Digest()), + public static + IESEngine createEngine() { + return new IESEngine(new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()), new HMac(new SHA512Digest())); + } + + /** + * Uses SHA512 + */ + public static + IESEngine createEngine(PaddedBufferedBlockCipher aesEngine) { + return new IESEngine(new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()), new HMac(new SHA512Digest()), aesEngine); } /** * These parameters are shared between the two parties. These are a NONCE (use ONCE number!!) */ - public static final IESParameters generateSharedParameters(SecureRandom secureRandom) { + public static + IESParameters generateSharedParameters(SecureRandom secureRandom) { int macSize = Crypto.ECC.macSize; // must be the MAC size // MUST be random EACH TIME encrypt/sign happens! - byte[] derivation = new byte[macSize/8]; - byte[] encoding = new byte[macSize/8]; + byte[] derivation = new byte[macSize / 8]; + byte[] encoding = new byte[macSize / 8]; secureRandom.nextBytes(derivation); secureRandom.nextBytes(encoding); @@ -1289,11 +1328,12 @@ public class Crypto { /** * AES-256 ONLY! */ - public static IESWithCipherParameters generateSharedParametersWithCipher(SecureRandom secureRandom) { + public static + IESWithCipherParameters generateSharedParametersWithCipher(SecureRandom secureRandom) { int macSize = Crypto.ECC.macSize; // must be the MAC size - byte[] derivation = new byte[macSize/8]; // MUST be random EACH TIME encrypt/sign happens! - byte[] encoding = new byte[macSize/8]; + byte[] derivation = new byte[macSize / 8]; // MUST be random EACH TIME encrypt/sign happens! + byte[] encoding = new byte[macSize / 8]; secureRandom.nextBytes(derivation); secureRandom.nextBytes(encoding); @@ -1302,17 +1342,17 @@ public class Crypto { } - public static final AsymmetricCipherKeyPair generateKeyPair(String eccCurveName, SecureRandom secureRandom) { + public static + AsymmetricCipherKeyPair generateKeyPair(String eccCurveName, SecureRandom secureRandom) { ECParameterSpec eccSpec = ECNamedCurveTable.getParameterSpec(eccCurveName); return generateKeyPair(eccSpec, secureRandom); } - public static final AsymmetricCipherKeyPair generateKeyPair(ECParameterSpec eccSpec, SecureRandom secureRandom) { - ECKeyGenerationParameters ecParams = new ECKeyGenerationParameters(new ECDomainParameters(eccSpec.getCurve() , - eccSpec.getG(), - eccSpec.getN()), - secureRandom); + public static + AsymmetricCipherKeyPair generateKeyPair(ECParameterSpec eccSpec, SecureRandom secureRandom) { + ECKeyGenerationParameters ecParams = new ECKeyGenerationParameters(new ECDomainParameters(eccSpec.getCurve(), eccSpec.getG(), + eccSpec.getN()), secureRandom); ECKeyPairGenerator ecKeyGen = new ECKeyPairGenerator(); ecKeyGen.init(ecParams); @@ -1325,8 +1365,9 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] encrypt(IESEngine eccEngine, CipherParameters private1, CipherParameters public2, - IESParameters cipherParams, byte[] message) { + public static + byte[] encrypt(IESEngine eccEngine, CipherParameters private1, CipherParameters public2, IESParameters cipherParams, + byte[] message) { eccEngine.init(true, private1, public2, cipherParams); @@ -1343,8 +1384,9 @@ public class Crypto { * * @return empty byte[] if error */ - public static final byte[] decrypt(IESEngine eccEngine, CipherParameters private2, CipherParameters public1, - IESParameters cipherParams, byte[] encrypted) { + public static + byte[] decrypt(IESEngine eccEngine, CipherParameters private2, CipherParameters public1, IESParameters cipherParams, + byte[] encrypted) { eccEngine.init(false, private2, public1, cipherParams); @@ -1356,7 +1398,8 @@ public class Crypto { } } - public static final boolean compare(ECPrivateKeyParameters privateA, ECPrivateKeyParameters privateB) { + public static + boolean compare(ECPrivateKeyParameters privateA, ECPrivateKeyParameters privateB) { ECDomainParameters parametersA = privateA.getParameters(); ECDomainParameters parametersB = privateB.getParameters(); @@ -1390,7 +1433,8 @@ public class Crypto { /** * @return true if publicA and publicB are NOT NULL, and are both equal to eachother */ - public static final boolean compare(ECPublicKeyParameters publicA, ECPublicKeyParameters publicB) { + public static + boolean compare(ECPublicKeyParameters publicA, ECPublicKeyParameters publicB) { if (publicA == null || publicB == null) { return false; } @@ -1445,7 +1489,8 @@ public class Crypto { return true; } - public static final boolean compare(IESParameters cipherAParams, IESParameters cipherBParams) { + public static + boolean compare(IESParameters cipherAParams, IESParameters cipherBParams) { if (!Arrays.equals(cipherAParams.getDerivationV(), cipherBParams.getDerivationV())) { return false; } @@ -1459,22 +1504,24 @@ public class Crypto { return true; } - public static final boolean compare(IESWithCipherParameters cipherAParams, IESWithCipherParameters cipherBParams) { + public static + boolean compare(IESWithCipherParameters cipherAParams, IESWithCipherParameters cipherBParams) { if (cipherAParams.getCipherKeySize() != cipherBParams.getCipherKeySize()) { return false; } // only need to cast one side. - return compare((IESParameters)cipherAParams, cipherBParams); + return compare((IESParameters) cipherAParams, cipherBParams); } /** * The message will have the (digestName) hash calculated and used for the signature. - * + *

* The returned signature is the {r,s} signature array. */ - public static final BigInteger[] generateSignature(String digestName, ECPrivateKeyParameters privateKey, SecureRandom secureRandom, byte[] bytes) { + public static + BigInteger[] generateSignature(String digestName, ECPrivateKeyParameters privateKey, SecureRandom secureRandom, byte[] bytes) { Digest digest = DigestFactory.getDigest(digestName); @@ -1488,18 +1535,18 @@ public class Crypto { /** * The message will use the bytes AS THE HASHED VALUE to calculate the signature. - * + *

* The returned signature is the {r,s} signature array. */ - public static final BigInteger[] generateSignatureForHash(ECPrivateKeyParameters privateKey, SecureRandom secureRandom, byte[] hashBytes) { + public static + BigInteger[] generateSignatureForHash(ECPrivateKeyParameters privateKey, SecureRandom secureRandom, byte[] hashBytes) { ParametersWithRandom param = new ParametersWithRandom(privateKey, secureRandom); ECDSASigner ecdsa = new ECDSASigner(); ecdsa.init(true, param); - BigInteger[] signature = ecdsa.generateSignature(hashBytes); - return signature; + return ecdsa.generateSignature(hashBytes); } /** @@ -1508,7 +1555,8 @@ public class Crypto { * @param signature is the {r,s} signature array. * @return true if the signature is valid */ - public static final boolean verifySignature(String digestName, ECPublicKeyParameters publicKey, byte[] message, BigInteger[] signature) { + public static + boolean verifySignature(String digestName, ECPublicKeyParameters publicKey, byte[] message, BigInteger[] signature) { Digest digest = DigestFactory.getDigest(digestName); @@ -1527,14 +1575,14 @@ public class Crypto { * @param signature is the {r,s} signature array. * @return true if the signature is valid */ - public static final boolean verifySignatureHash(ECPublicKeyParameters publicKey, byte[] hash, BigInteger[] signature) { + public static + boolean verifySignatureHash(ECPublicKeyParameters publicKey, byte[] hash, BigInteger[] signature) { ECDSASigner ecdsa = new ECDSASigner(); ecdsa.init(false, publicKey); - boolean verifySignature = ecdsa.verifySignature(hash, signature[0], signature[1]); - return verifySignature; + return ecdsa.verifySignature(hash, signature[0], signature[1]); } } @@ -1544,45 +1592,51 @@ public class Crypto { * An implementation of the scrypt * key derivation function. */ - public static class SCrypt { + public static final + class SCrypt { + + private + SCrypt() { + } /** * Hash the supplied plaintext password and generate output using default parameters - *

+ *

* The password chars are no longer valid after this call * - * @param password Password. - * @param salt Salt parameter + * @param password Password. */ - public static final String encrypt(char[] password) { + public static + String encrypt(char[] password) { return encrypt(password, 16384, 32, 1); } /** * Hash the supplied plaintext password and generate output using default parameters - *

+ *

* The password chars are no longer valid after this call * - * @param password Password. - * @param salt Salt parameter + * @param password Password. + * @param salt Salt parameter */ - public static final String encrypt(char[] password, byte[] salt) { + public static + String encrypt(char[] password, byte[] salt) { return encrypt(password, salt, 16384, 32, 1, 64); } /** * Hash the supplied plaintext password and generate output. - *

+ *

* The password chars are no longer valid after this call * - * @param password Password. - * @param N CPU cost parameter. - * @param r Memory cost parameter. - * @param p Parallelization parameter. - * + * @param password Password. + * @param N CPU cost parameter. + * @param r Memory cost parameter. + * @param p Parallelization parameter. * @return The hashed password. */ - public static final String encrypt(char[] password, int N, int r, int p) { + public static + String encrypt(char[] password, int N, int r, int p) { SecureRandom secureRandom = new SecureRandom(); byte[] salt = new byte[32]; secureRandom.nextBytes(salt); @@ -1592,19 +1646,19 @@ public class Crypto { /** * Hash the supplied plaintext password and generate output. - *

+ *

* The password chars are no longer valid after this call * - * @param password Password. - * @param salt Salt parameter - * @param N CPU cost parameter. - * @param r Memory cost parameter. - * @param p Parallelization parameter. - * @param dkLen Intended length of the derived key. - * + * @param password Password. + * @param salt Salt parameter + * @param N CPU cost parameter. + * @param r Memory cost parameter. + * @param p Parallelization parameter. + * @param dkLen Intended length of the derived key. * @return The hashed password. */ - public static final String encrypt(char[] password, byte[] salt, int N, int r, int p, int dkLen) { + public static + String encrypt(char[] password, byte[] salt, int N, int r, int p, int dkLen) { // Note: this saves the char array in UTF-16 format of bytes. // can't use password after this as it's been changed to '*' byte[] passwordBytes = Crypto.Util.charToBytesPassword(password); @@ -1624,12 +1678,12 @@ public class Crypto { /** * Compare the supplied plaintext password to a hashed password. * - * @param password Plaintext password. - * @param hashed scrypt hashed password. - * + * @param password Plaintext password. + * @param hashed scrypt hashed password. * @return true if password matches hashed value. */ - public static final boolean verify(char[] password, String hashed) { + public static + boolean verify(char[] password, String hashed) { // Note: this saves the char array in UTF-16 format of bytes. // can't use password after this as it's been changed to '*' byte[] passwordBytes = Crypto.Util.charToBytesPassword(password); @@ -1646,7 +1700,7 @@ public class Crypto { int N = (int) Math.pow(2, params >> 16 & 0xFF); int r = params >> 8 & 0xFF; - int p = params & 0xFF; + int p = params & 0xFF; int length = derived0.length; if (length == 0) { @@ -1667,12 +1721,25 @@ public class Crypto { return result == 0; } - private static final int log2(int n) { + private static + int log2(int n) { int log = 0; - if ((n & 0xFFFF0000 ) != 0) { n >>>= 16; log = 16; } - if (n >= 256) { n >>>= 8; log += 8; } - if (n >= 16 ) { n >>>= 4; log += 4; } - if (n >= 4 ) { n >>>= 2; log += 2; } + if ((n & 0xFFFF0000) != 0) { + n >>>= 16; + log = 16; + } + if (n >= 256) { + n >>>= 8; + log += 8; + } + if (n >= 16) { + n >>>= 4; + log += 4; + } + if (n >= 4) { + n >>>= 2; + log += 2; + } return log + (n >>> 1); } @@ -1680,16 +1747,16 @@ public class Crypto { /** * Pure Java implementation of the scrypt KDF. * - * @param password Password. - * @param salt Salt. - * @param N CPU cost parameter. - * @param r Memory cost parameter. - * @param p Parallelization parameter. - * @param dkLen Intended length of the derived key. - * + * @param password Password. + * @param salt Salt. + * @param N CPU cost parameter. + * @param r Memory cost parameter. + * @param p Parallelization parameter. + * @param dkLen Intended length of the derived key. * @return The derived key. */ - public static byte[] encrypt(byte[] password, byte[] salt, int N, int r, int p, int dkLen) { + public static + byte[] encrypt(byte[] password, byte[] salt, int N, int r, int p, int dkLen) { if (N == 0 || (N & N - 1) != 0) { throw new IllegalArgumentException("N must be > 0 and a power of 2"); } @@ -1705,7 +1772,7 @@ public class Crypto { return org.bouncycastle.crypto.generators.SCrypt.generate(password, salt, N, r, p, dkLen); } finally { // now zero out the bytes in password. - Arrays.fill(password, (byte)0); + Arrays.fill(password, (byte) 0); } } }