Greetings,
On Android, we can't specify AES128 or AES256. But is AES128, or AES256 actually run when using "AES/CBC/PKCS5Padding"?
I tried something like below
SecretKeyFactory sf = SecretKeyFactory.getInstance("PBEWITHSHAAND256BITAES-CBC-BC");
KeySpec ks = new PBEKeySpec(masterPassword.toCharArray(),k1,1320,256);
secKey = sf.generateSecret(ks);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secKey, generateIV(cipher));
The SecretKeyFactory created has a keySize of 256, and the keyLength specified in PBEKeySpec seems doesn't matter. No matter 256 or 128, or any other positive number, the secKey generated always has 256 keySize. Since we passed the secKey to initialize the cipher, so now, does the encryption will be run using AES128, or AES256?
Thanks!
This article should allow you to determine the strengths and ciphers you have available in the runtime image. I don't know if it will kick you out at this point but by specifying PBEKeySpec with a length of 256 I think you might have it.
On Android, we can't specify AES128 or
AES256. But is AES128, or AES256
actually run when using
"AES/CBC/PKCS5Padding"?
Am I wrong suggesting that none is actually determined at getInstance()? I suppose the length of the cipher's key will be determined only after call to init() where you set a key which is of certain length.
Related
I'm trying to implement in swift the equivalent of my code in java. Basically is an AES implementation with GCM padding and I'm using a key derivation for that. In swift I'm using the CryptoSwift library.
My issue is that I cannot get the same encrypted text in swift.
After a very long research I couldn't find any solutions for my problem, I even saw the test code of the CryptoSwift library repository to get any ideas but with no luck
This is my java code:
GCMParameterSpec ivParameterSpec = new GCMParameterSpec(128, "ivVector".getBytes());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec("myPassword".toCharArray(), "salt".getBytes(), 1000, 256);
SecretKey tmp = secretKeyFactory.generateSecret(keySpec);
key = new SecretKeySpec(tmp.getEncoded(), "AES");
encryptCipher = Cipher.getInstance("AES/GCM/NoPadding");
encryptCipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
byte[] encryptedWord = Base64.encode(encryptCipher.doFinal("example".getBytes("UTF-8")));
And this is my swift code:
do{
keyDerivation = try PKCS5.PBKDF2(password: "myPassword".bytes, salt: "salt".bytes, iterations: 1000, keyLength: 32, variant: .sha1).calculate()
let gcm = GCM(iv: keyDerivation, mode: .combined)
let aes = try AES(key: keyDerivation, blockMode: gcm, padding: .noPadding)
let encryptedText = try aes.encrypt("example".bytes)
}catch{
print(error)
}
Any help would be appreciated.
Your IV doesn't match in both cases. In Java you use a string, and in Swift you use the derived key in keyDerivation.
Furthermore, you should make sure that you use the same character encoding. I'd not use getBytes or similar for either language. Explicitly specifying UTF-8 is probably best.
Note that the Java PBKDF2WithHmacSHA1 may handle password encoding in a rather peculiar way, so some kind of input validation on the password is probably in order.
Needless to say, the salt should be random for each call to encrypt, not static. I presume this is just test code though.
I am trying to encrypt data and send them to the server bye using 256 bits blowfish, but I do not know what is the proper provider for the key size. I have tried to change the CFB32 and CFB8 but does not work I have tried iv with 8 16 and 32 but it does not work. I have tried OAEPWithSHA-256AndMGF1Padding also it did not work.
and when I used blowfish/ECB/PKCS1Padding it gave me message that can not find any provider support blowfish/ECB/PKCS1Padding.
// Create a Blowfish key
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
// Now set the keysize to 256 bits
keyGenerator.init(256);
Key key = keyGenerator.generateKey();
System.out.println("Done generating the key.");
// Create a cipher using that key to initialize it
Cipher cipher = Cipher.getInstance("Blowfish/CFB8/NoPadding");
//Cipher encrypter = Cipher.getInstance("Blowfish/C/NoPadding");
System.out.println("good here");
SecureRandom random = new SecureRandom();
byte[] iv = new byte[16];
random.nextBytes(iv);
IvParameterSpec spec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key,spec);
If you get the "java.security.InvalidKeyException: Illegal key size" when trying to use key size of 256, then you need to to download JCE Unlimited Strength Jurisdiction Policy Files for your JDK/JRE. The unlimited policy will allow you to use key sizes greater than the predefined limits (128 bits for blowfish).
The Oracle JDK 7 unlimited JCE policy can be downloaded here, make sure to read the readme.txt included in the archive and follow the instuctions.
If you get the "java.security.InvalidAlgorithmParameterException: Wrong IV length: must be ??? bytes long" then you have a mismatch between the actual IV array length and the IV length expected by the mode and padding specified in the Cipher.getInstance() argument. For "Blowfish/CFB8/NoPadding" the IV should be 8 bytes long, but in your code you create a 16-bytes long IV array.
If you have some other problems then you should really update your question and specify what the actual problem is and what the actual exception (preferably with the stacktrace) is.
For 256 bit Keysize, need to add JCE jar in project and referred code will work for that.
JCE Jar : http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
BlowfishUtility: https://github.com/NikhilPareek88/BlowfishUtility
I have a legacy code in ruby that does the encryption using OpenSSL
However, I would like to translate this in Java and I am lost.
so far my biggest blocker is figuring out how to generate the IV based on this code.
Any help would be greatly appreciated
def func_enc(data, key)
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.encrypt
cipher.pkcs5_keyivgen(key)
cipher.update(data)
encrypted_data << cipher.final
return encryptedData
end
EDIT
Just to clarify, I would like to use Java Crypto for this. This is the code I came up with so far:
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithMD5And256AES-CBC");
KeySpec spec = new PBEKeySpec("Password".toCharArray(), null, 2048, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
but "PBKDF2WithMD5And256AES-CBC" does not have any provider and I get NoSuchAlgorithm exception.
java.security.NoSuchAlgorithmException: PBKDF2WithMD5And256AES-CBC SecretKeyFactory not available
Also the salt that pkcs5_keyivgen uses by default is null!! I am not sure if Java lets me use a null salt.
How can I generate the correct IV ?
The warning on this documentation page suggests that the deprecated pkcs5_keyivgen method does something non-standard when used together with AES. First of all, it uses PBKDF1, not PBKDF2.
It might be difficult to replicate what it does, and implementing cryptographic algorithms is generally inadvisable unless you know exactly what you're doing – even experts often get it wrong.
How should I encrypt a session key on the client side with the public key transported from server side?
Should I use Cipher.WRAP_MODE or Cipher.ENCRYPT_MODE?
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.WRAP_MODE, publicKey);
byte[] wrappedSessionKey = cipher.wrap(sessionKey);
I am not really sure how to use encrypt_mode to encrypt sessionKey. Could someone help me on this?
Wrapping and encrypting are very similar, however wrapping expresses more precisely what you are planning to do. General "encryption" operates on raw data with no semantic meaning, whereas wrapping is known to relate to keys. Hence the Cipher.unwrap() method returns a Key not a byte array.
Your code will be more portable (particular with respect to hardware security modules) if you use wrap for doing key wrapping. In some circumstances, key permissions will allow a wrapping operation but not a raw encryption of the key bytes.
Of course, since the entirety of the JCE architecture is based on a provider concept, you will need to check exactly what algorithm to specify for your chosen provider to get the output format you want. This is particularly important if you are sending the wrapped key data to a third-party.
In your particular case, the same behaviour will be exhibited by both WRAP and ENCRYPT, as demonstrated below, where I interchange the results:
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "SunJSSE");
generator.initialize(2048);
KeyPair keyPair = generator.generateKeyPair();
SecretKey sessionKey = new SecretKeySpec(new byte[16], "AES");
Cipher c = Cipher.getInstance("RSA", "SunJCE");
c.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] result1 = c.doFinal(sessionKey.getEncoded());
c.init(Cipher.WRAP_MODE, keyPair.getPublic());
byte[] result2 = c.wrap(sessionKey);
c.init(Cipher.UNWRAP_MODE, keyPair.getPrivate());
SecretKey sessionKey1 = (SecretKey) c.unwrap(result1, "AES",
Cipher.SECRET_KEY);
c.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
SecretKey sessionKey2 = new SecretKeySpec(c.doFinal(result2), "AES");
System.out.println(Arrays.equals(sessionKey1.getEncoded(),
sessionKey2.getEncoded()));
This prints: true
Recently upgraded from BC 1.34 to 1.45. I'm decoding some previously-encoded data with the following:
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
When using BC 1.45 I get this exception:
javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:715)
at javax.crypto.Cipher.doFinal(Cipher.java:1090)
EDIT: More about this issue. I am using the following to generate raw keys from a passphrase:
KeyGenerator kgen = KeyGenerator.getInstance("AES", "BC");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
What I have found is that this results in two different values for BC 1.34 vs 1.45.
It might also not be BouncyCastle-related (I am testing on Android 2.3)
I just finished tracking this down. It's because of a bug fix on line 320 (in Gingerbread source) of SHA1PRNG_SecureRandomImpl.java in the engineNextBytes() method where
bits = seedLength << 3 + 64;
was changed to
bits = (seedLength << 3) + 64;
Clearly it was a bug that was fixed, but it means that given the same seed, SecureRandom will generate different data pre- and post-gingerbread.
I have a "fix" for it. I stole enough code from android-7 to be able to generate random bytes in the same way that SecureRandom did. I try to decrypt my information and if it fails, use my jacked up SecureRandom to decrypt it. Then I can obviously reencrypt it using the newer SecureRandom, although I'm kind of thinking of moving away from SecureRandom entirely...
Looks like the problem is SecureRandom not being portable across the Froyo-Gingerbread boundary. This post describes a similar problem:
http://groups.google.com/group/android-security-discuss/browse_thread/thread/6ec015a33784b925
I am not sure what exactly changed in SecureRandom, but the only way I found to fix it was to reencrypt the data with keys generated using a portable method.
According to the release notes, this fix was included in version 1.40:
PKCS7Padding validation would not fail if pad length was 0. This has been fixed.
This sounds like it may be pertinent.