Determinisric AES-CTR in Java BouncyCastle? - java

I have been using aes-js in Node to encrypt/decrypt using AES counter mode.
As you can see in the example, I'm using it without padding and I can specify which block (0 in this case) I want to start with.
var aesCTR = new aesjs.ModeOfOperation.ctr(keyBytes, new aesjs.Counter(0));
var encryptedBytes = aesCTR.encrypt(plaintextBytes);
I wanted to reproduce the same behavior above in Java. I'm using BouncyCastle like the example below.
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted=cipher.doFinal(msgBytes);
But this implementation doesn't seem to be outputting the sames values as the one above. Plus it seems to increment the counter automatically each run (undesirable behavior in this case).
Is there a way to match the Node JS implementation using Java ?

You should get the same behaviour if you provide an IV / initial ctr value that is all zero e.g:
byte[] iv = new byte[16];
Arrays.fill(iv, (byte)0);
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encrypted=cipher.doFinal(msgBytes);
The way it is set up in your code, a random IV is generated every time you call init().
BTW, if you omit BC, you will get the stock AES implementation

Related

Why AES Produce Different result and Why DES not Produce

I'm trying to change encryption algorithm of existing project. But i have a little bit confusion. When i use "PBEWithHmacSHA512AndAES_256" as a parameter, it produce different result but when i use "PBEWithMD5AndDES" as a parameter it produce same result. My functions are :
public static synchronized String encrypt1(final String textToEncrypt, final String pathPublicKey) throws Exception {
final KeySpec pbeKeySpec = new PBEKeySpec(DbKeyHandler.getDbKey(pathPublicKey).toCharArray());
final SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(pbeKeySpec);
// Prepare the parameter to the ciphers
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
final Cipher cipher = Cipher.getInstance(pbeKey.getAlgorithm());
// Create the ciphers
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);
// Encode the string into bytes using utf-8
final byte[] utf8 = textToEncrypt.getBytes("UTF8");
// Encrypt
final byte[] enc = cipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
}
public static synchronized String encrypt2 (final String textToEncrypt, final String pathPublicKey) throws Exception {
final KeySpec pbeKeySpec = new PBEKeySpec(DbKeyHandler.getDbKey(pathPublicKey).toCharArray());
final SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithHmacSHA512AndAES_256").generateSecret(pbeKeySpec);
// Prepare the parameter to the ciphers
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
final Cipher cipher = Cipher.getInstance(pbeKey.getAlgorithm());
// Create the ciphers
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);
// Encode the string into bytes using utf-8
final byte[] utf8 = textToEncrypt.getBytes("UTF8");
// Encrypt
final byte[] enc = cipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
}
Any suggestions, ideas will help me to figure out what's going on here.
Also this is produce different results:
KeyStore keyStore = KeyStore.getInstance("JCEKS");
keyStore.load(new FileInputStream((pathOfJKSfile)), password.toCharArray());
Key key = keyStore.getKey(keyName, keyPass.toCharArray());
byte[] raw = key.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "PBEWithHmacSHA512AndAES_256");
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);
final Cipher cipherEncrypt = Cipher.getInstance(ALGORITHM);
cipherEncrypt.init(Cipher.ENCRYPT_MODE, secretKeySpec, paramSpec);
final byte[] enc = cipherEncrypt.doFinal(messageBytes);
System.out.println( new sun.misc.BASE64Encoder().encode(enc));
And i know that cipher.init() using "JceSecurity.RANDOM" for pruducing different results.
Both algorithms, PBEWithHmacSHA512AndAES_256 and PBEWithMD5AndDES, first generate an encryption key by processing a password, a salt and an iteration count (using HmacSHA512 and MD5, respectively) and then encrypt the plain text (with AES-256 and DES, respectively) using this key and the CBC-mode. When the Cipher-instance is initialized, a pseudo-random initialization vector (IV) is generated that is required for the CBC- mode.
In the context of PBEWithHmacSHA512AndAES_256, the IV is generated using the SecureRandom implementation of the highest-priority installed provider, at least for the Cipher#init()-method used in the code (note that there are several overloads of the Cipher#init()-method and that a SecureRandom-instance can also be passed explicitly). I.e. with each Cipher-initialization a new (random) IV is generated and therefore the encrypted text is always different, even for an identical plain text. For this reason, the encrypted text in your examples changes in this context.
In the context of PBEWithMD5AndDES, the IV is only determined by the password, the salt, the iteration count (and of course the MD5-hash-algorithm itself). Therefore, the IV and the encrypted text do not change in case of repetition (provided that password, salt, iteration count etc. are the same). For this reason, the encrypted text in your example does not change in this context.
The generation of a new, random IV during the Cipher-initalization makes sense with regard to the following requirements for the IV: For security reasons, an IV in CBC-mode (btw this also applies to other modes) may only be used once under the same key. In addition the IV must be unpredictable.
PBEWithMD5AndDES is deprecated.
EDIT:
The use of an IV is standard nowadays (for security reasons). A lot of information can be found on the Internet on this topic e.g. here. In the following I will only describe a few basic things.
The IV used for encryption must be stored in some way because it is required for decryption. The IV does not have to be kept secret, so that it is usually concatenated with the encrypted data (e.g. before the encrypted data) and stored together with them. During decryption, both parts can be separated because the length of the IV is known (16 Byte for AES). E.g for the concatenation in the encryption-method something like the following is used (let iv and enc be the byte-arrays with the IV and the encrypted data, respectively):
byte[] result = new byte[enc.length + iv.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(enc, 0, result, iv.length, enc.length);
and in the decryption-method the corresponding counterpart (having in mind that the length of an IV in AES is 16 Byte).
In the encryption-method the IV can be determined with Cipher#getIV() (this must of course happen after calling Cipher#init()).
In the decryption-method you have to pass the IV to the PBEParameterSpec-ctor (e.g. let iv be the byte-array with the IV):
IvParameterSpec ivSpec = new IvParameterSpec(iv);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount, ivSpec);
The generation of an IV can also take place outside the Cipher-class, see e.g. Generating random IV for AES in Java. Then you have to pass that IV in the encryption-method in the same way as above described for the decryption-method.
Note, in connection with an IV some points have to be considered e.g. using a mode without an IV (e.g. ECB), using an IV consisting exclusively of 0-values, using a predictable IV or using an IV more than once under the same key etc. drastically reduces security in general, see e.g. here!

PBEWITHHMACSHA512ANDAES_128 and Initialization Vector

I am working with the PBEWITHHMACSHA512ANDAES_128 excryption method from Java 8 If I initialize a KeySpec and Cipher object as follows:
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithHmacSHA512AndAES_128");
KeySpec spec = new PBEKeySpec(PASSWORD.toCharArray(), SALT.getBytes(), 4096, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(),"PBEWithHmacSHA512AndAES_128" );
Cipher cipher = Cipher.getInstance("PBEWITHHMACSHA512ANDAES_128");
cipher.init(Cipher.ENCRYPT_MODE, secret);
I can encrypt and decrypt within the same execution of a Java program, however once the program completes, any data encrypted will be irretrievable.
My first assumption was that the JRE was selecting a random IV since it is required for block ciphers, but attempting to retrieve the IV with:
cipher.getParameters().getParameterSpec(IvParameterSpec.class);
Yields an InvalidParameterSpecException. The only way to get to decryptable data is to specify an IvParameterSpec wrapped by a PBEParameterSpec (passing an IvParameterSpec alone gives an InvalidAlgorithmParameterException).
Is passing the PBEParameterSpec the correct way to specify the IV and what would be the purpose in permitting users to not specify an IV when it is needed?
Thanks
By default PBEWITHHMACSHA512ANDAES_128 uses CBC mode and PKCS5Padding.
You are right, according to the Java source code PBES2Core.java an random IV is used.
If you want to specify your own IV you have to do it this way (which uses an IV of null bytes):
KeySpec spec = new PBEKeySpec(PASSWORD.toCharArray());
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "PBEWithHmacSHA512AndAES_128");
Cipher cipher = Cipher.getInstance("PBEWITHHMACSHA512ANDAES_128");
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
PBEParameterSpec pbeSpec = new PBEParameterSpec(SALT.getBytes(), 4096, iv);
cipher.init(Cipher.ENCRYPT_MODE, secret, pbeSpec);

Decrypting Blowfish/CBC in Java

I have Perl code that decrypts a String and I want to do the same in Java. This is the Perl code:
my $c = Crypt::CBC->new( -key => $keyString, -cipher => 'Blowfish', -header => 'randomiv');
return $c->decrypt_hex($config->{encrypted_password})
This is my attempt at the Java code:
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
// setup an IV (initialization vector) that should be
// randomly generated for each input that's encrypted
byte[] iv = new byte[cipher.getBlockSize()];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// decrypt
SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(keyString), "Blowfish");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.decodeBase64(input));
return Hex.encodeHexString(decrypted);
I'm getting:javax.crypto.BadPaddingException: Given final block not properly padded. But according to this, the Crypt CBC library uses PKCS5 as the default padding.
Also, am I doing the hex encoding at the end right?
One of the problems you have is that you generate a random IV instead of importing the one used for encryption. Do you have access to the IV used at encryption? Could it be at the start of the ciphertext?
I don't do Perl, so I'm not quite sure if my response is valid. Base64 is probably not the right decoding you're looking for.
For creating your SecretKeySpec, try doing something like:
SecretKey secretKey = new SecretKeySpec(keyString.getBytes("ASCII"), "Blowfish");
For decoding the text, check out Hex.decodeHex(char[]) which can be found at http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Hex.html ... so your code might look something like this:
byte[] decrypted = cipher.doFinal(Hex.decodeHex(input.toCharArray()));
String unencryptedStuff = new String(decrypted);

Android: Encrypt a string with AES 256bit Encryption with iv and secret key

SecureRandom random = new SecureRandom(); // quite heavy, look into a lighter method.
String stringToEncrypt = "mypassword";
byte[] realiv = new byte[16];
random.nextBytes(realiv);
Cipher ecipher = Cipher.getInstance("AES");
SecureRandom random = new SecureRandom(); // quite heavy, look into a lighter method.
byte[] realiv = new byte[16];
random.nextBytes(realiv);
byte[] secret = "somelongsecretkey".getBytes();
SecretKeySpec secretKey = new SecretKeySpec(secret, "AES");
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, random);
byte[] encryptedData = ecipher.doFinal();
but the init() only takes in 3 parameters. I need a way to do something like:
ecipher.init(Cipher.ENCRYPT_MODE, stringToEncrypt, secretKey, random);
In general you don't need something that generates random numbers for an algorithm that has deterministic behavior. Furthermore, you don't need an IV when you are using ECB block mode, which is what Java defaults to. To be precise, Java defaults to "AES/ECB/PKCS5Padding" for in Cipher.getInstance("AES").
So you should be OK with code like this:
// lets use the actual key value instead of the platform specific character decoding
byte[] secret = Hex.decodeHex("25d6c7fe35b9979a161f2136cd13b0ff".toCharArray());
// that's fine
SecretKeySpec secretKey = new SecretKeySpec(secret, "AES");
// SecureRandom should either be slow or be implemented in hardware
SecureRandom random = new SecureRandom();
// first create the cipher
Cipher eCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// filled with 00h characters first, use Cipher instance so you can switch algorithms
byte[] realIV = new byte[eCipher.getBlockSize()];
// actually fill with random
random.nextBytes(realIV);
// MISSING: create IvParameterSpec
IvParameterSpec ivSpec = new IvParameterSpec(realIV);
// create the cipher using the IV
eCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
// NOTE: you should really not encrypt passwords for verification
String stringToEncrypt = "mypassword";
// convert to bytes first, but don't use the platform encoding
byte[] dataToEncrypt = stringToEncrypt.getBytes(Charset.forName("UTF-8"));
// actually do the encryption using the data
byte[] encryptedData = eCipher.doFinal(dataToEncrypt);
Now that looks a whole lot better. I've used the Apache commons codec for decoding the hexadecimal string.
Note that you need to save the realIV with the encryptedData, and that you haven't included integrity protection, e.g. a MAC (for passwords, you may not need that though).
I strongly suspect that what you want to do is call ecipher.doFinal(stringToEncrypt), possibly after a series of doUpdate(...) if you have longer strings.
.init() creates the cipher object, update() and doFinal() populate the encrypted output and take the plaintext as input.
Of course, you'll need to convert between String and a byte array.

Ruby Equivalent

I am in the process of implementing a Java library in Ruby. I have come across the following road block. Is it possible to implement the following code in ruby? Are there any ruby equivalents for byte[], IvParameterSpec, SecretKeySpec ?
private String decrypt(String token)
{
//parse token into its IV and token components
byte[] ivAndToken = Base64.decodeBase64(token);
byte[] iv = new byte[ivLength];
System.arraycopy(ivAndToken, 0, iv, 0, ivLength);
int length = ivAndToken.length - ivLength;
byte[] tokenBytes = new byte[length];
System.arraycopy(ivAndToken, ivLength, tokenBytes, 0, length);
//prepare initialization vector specification
IvParameterSpec spec = new IvParameterSpec(iv);
//create cipher instance based on transformer params
Cipher cipher = Cipher.getInstance(algorithm + mode + padding, CRYPTO_PROVIDER);
//convert key bytes into valid key format
Key key = new SecretKeySpec(Base64.decodeBase64(symkey), algorithm);
//initialize cipher for decryption
cipher.init(Cipher.DECRYPT_MODE, key, spec);
//decrypt the payload
String plaintext = new String(cipher.doFinal(tokenBytes));
return plaintext;
}
You'll probably have to implement both IvParameterSpec and SecretKeySpec on Ruby if you want the algorithm to behave exactly like it does in Java. byte[] is of course just a byte array. You'll probably want to at the docs for them (links above) and also hopefully you understand block cipher operation modes work.
If you don't, SecretKey refers to the symmetric key (eg: the passphrase), and IV is the initialization vector, a cryptographic nonce used to make different encryptions of the same plaintext generate different ciphertext. IV's are needed for all operation modes except ECB. See this wikipedia page for more details.

Categories

Resources