Skip to content

Commit 212b04c

Browse files
committed
Changing the migration logic as follows:
1 parent 967e166 commit 212b04c

File tree

2 files changed

+30
-145
lines changed

2 files changed

+30
-145
lines changed

auth0/src/main/java/com/auth0/android/authentication/storage/CryptoUtil.java

Lines changed: 30 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -366,98 +366,46 @@ byte[] RSAEncrypt(byte[] decryptedInput) throws IncompatibleDeviceException, Cry
366366
@VisibleForTesting
367367
byte[] getAESKey() throws IncompatibleDeviceException, CryptoException {
368368
String encodedEncryptedAES = storage.retrieveString(KEY_ALIAS);
369-
if (TextUtils.isEmpty(encodedEncryptedAES)) {
370-
encodedEncryptedAES = storage.retrieveString(OLD_KEY_ALIAS);
371-
}
372-
byte[] decryptedAESKey = null;
373-
boolean migrationNeeded = false;
374-
if (encodedEncryptedAES != null) {
375-
//Return existing key
369+
if (!TextUtils.isEmpty(encodedEncryptedAES)) {
376370
byte[] encryptedAESBytes = Base64.decode(encodedEncryptedAES, Base64.DEFAULT);
377-
try {
378-
decryptedAESKey = RSADecrypt(encryptedAESBytes);
379-
}catch (IncompatibleDeviceException e){
380-
Log.w(TAG, "Failed to decrypt AES key with OAEP due to " +
381-
"IncompatibleDeviceException. Cause: "
382-
+ (e.getCause() != null ? e.getCause().getClass().getSimpleName() : "N/A")
383-
+ ". Attempting PKCS1 fallback for migration.", e);
384-
Throwable cause = e.getCause();
385-
if (cause instanceof InvalidKeyException) {
386-
try {
387-
KeyStore.PrivateKeyEntry rsaKeyEntry = getRSAKeyEntry();
388-
Cipher rsaPkcs1Cipher = Cipher.getInstance(OLD_PKCS1_RSA_TRANSFORMATION);
389-
rsaPkcs1Cipher.init(Cipher.DECRYPT_MODE, rsaKeyEntry.getPrivateKey());
390-
decryptedAESKey = rsaPkcs1Cipher.doFinal(encryptedAESBytes);
391-
migrationNeeded = true;
392-
} catch (Exception pkcs1Exception) {
393-
Log.e(TAG, "Failed to decrypt AES key with PKCS1Padding fallback.",
394-
pkcs1Exception);
395-
decryptedAESKey = null;
396-
}
397-
} else {
398-
throw e;
399-
}
400-
}catch (CryptoException e) {
401-
Log.w(TAG, "Failed to decrypt AES key with OAEP. Cause: " +
402-
(e.getCause() != null ? e.getCause().getClass().getSimpleName() : "N/A") +
403-
". Attempting PKCS1 fallback for migration.", e);
404-
Throwable cause = e.getCause();
405-
if (cause instanceof BadPaddingException || cause instanceof
406-
IllegalBlockSizeException || cause instanceof InvalidKeyException) {
407-
try {
408-
KeyStore.PrivateKeyEntry rsaKeyEntry = getRSAKeyEntry();
409-
Cipher rsaPkcs1Cipher = Cipher.getInstance(OLD_PKCS1_RSA_TRANSFORMATION);
410-
rsaPkcs1Cipher.init(Cipher.DECRYPT_MODE, rsaKeyEntry.getPrivateKey());
411-
decryptedAESKey = rsaPkcs1Cipher.doFinal(encryptedAESBytes);
412-
migrationNeeded = true;
413-
} catch (Exception pkcs1Exception) {
414-
Log.e(TAG, "Failed to decrypt AES key with PKCS1Padding fallback."
415-
, pkcs1Exception);
416-
decryptedAESKey = null;
417-
}
418-
} else {
419-
throw e;
420-
}
421-
}
422-
if (decryptedAESKey != null) {
423-
final int aesExpectedLengthInBytes = AES_KEY_SIZE / 8;
424-
if (decryptedAESKey.length != aesExpectedLengthInBytes) {
425-
Log.w(TAG, "Decrypted AES key has incorrect length (" +
426-
decryptedAESKey.length + " bytes, expected " + aesExpectedLengthInBytes
427-
+ "). Discarding.");
428-
decryptedAESKey = null;
429-
migrationNeeded = false;
430-
}
431-
}
371+
return RSADecrypt(encryptedAESBytes);
432372
}
433-
434-
if (migrationNeeded && decryptedAESKey != null) {
373+
String encodedOldAES = storage.retrieveString(OLD_KEY_ALIAS);
374+
if (!TextUtils.isEmpty(encodedOldAES)) {
435375
try {
436-
deleteRSAKeys();
376+
byte[] encryptedOldAESBytes = Base64.decode(encodedOldAES, Base64.DEFAULT);
377+
KeyStore.PrivateKeyEntry rsaKeyEntry = getRSAKeyEntry();
378+
Cipher rsaPkcs1Cipher = Cipher.getInstance(OLD_PKCS1_RSA_TRANSFORMATION);
379+
rsaPkcs1Cipher.init(Cipher.DECRYPT_MODE, rsaKeyEntry.getPrivateKey());
380+
byte[] decryptedAESKey = rsaPkcs1Cipher.doFinal(encryptedOldAESBytes);
437381

438382
byte[] encryptedAESWithOAEP = RSAEncrypt(decryptedAESKey);
439383
String newEncodedEncryptedAES = new String(Base64.encode(encryptedAESWithOAEP, Base64.DEFAULT), StandardCharsets.UTF_8);
440384
storage.store(KEY_ALIAS, newEncodedEncryptedAES);
441-
} catch (Exception reEncryptEx) {
442-
Log.e(TAG, "Failed to re-encrypt AES key with OAEP during migration. A new AES key will be generated.", reEncryptEx);
443-
decryptedAESKey = null;
385+
storage.remove(OLD_KEY_ALIAS);
386+
return decryptedAESKey;
387+
} catch (Exception e) {
388+
Log.e(TAG, "Could not migrate the legacy AES key. A new key will be generated.", e);
389+
deleteAESKeys();
444390
}
445391
}
446-
if (decryptedAESKey == null) {
447-
try {
448-
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM_AES);
449-
keyGen.init(AES_KEY_SIZE);
450-
decryptedAESKey = keyGen.generateKey().getEncoded();
451-
452-
byte[] encryptedNewAES = RSAEncrypt(decryptedAESKey);
453-
String encodedEncryptedNewAESText = new String(Base64.encode(encryptedNewAES, Base64.DEFAULT), StandardCharsets.UTF_8);
454-
storage.store(KEY_ALIAS, encodedEncryptedNewAESText);
455-
} catch (NoSuchAlgorithmException e) {
456-
Log.e(TAG, "Error while creating the new AES key.", e);
457-
throw new IncompatibleDeviceException(e);
458-
}
392+
393+
try {
394+
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM_AES);
395+
keyGen.init(AES_KEY_SIZE);
396+
byte[] decryptedAESKey = keyGen.generateKey().getEncoded();
397+
398+
byte[] encryptedNewAES = RSAEncrypt(decryptedAESKey);
399+
String encodedEncryptedNewAESText = new String(Base64.encode(encryptedNewAES, Base64.DEFAULT), StandardCharsets.UTF_8);
400+
storage.store(KEY_ALIAS, encodedEncryptedNewAESText);
401+
return decryptedAESKey;
402+
} catch (NoSuchAlgorithmException e) {
403+
Log.e(TAG, "Error while creating the new AES key.", e);
404+
throw new IncompatibleDeviceException(e);
405+
} catch (Exception e) {
406+
Log.e(TAG, "Unexpected error while creating the new AES key.", e);
407+
throw new CryptoException("Unexpected error while creating the new AES key.", e);
459408
}
460-
return decryptedAESKey;
461409
}
462410

463411

auth0/src/test/java/com/auth0/android/authentication/storage/CryptoUtilTest.java

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -349,26 +349,6 @@ public void shouldThrowOnInvalidAlgorithmParameterExceptionWhenTryingToObtainRSA
349349
});
350350
}
351351

352-
@Test
353-
public void shouldCreateAESKeyIfMissing() throws Exception {
354-
byte[] rsaEncryptedAesKey = "RSA-OAEP-encrypted-AES-key".getBytes(StandardCharsets.UTF_8);
355-
String base64EncodedRsaKey = "base64EncodedOaepAesKey";
356-
when(storage.retrieveString(KEY_ALIAS)).thenReturn(null);
357-
when(storage.retrieveString(OLD_KEY_ALIAS)).thenReturn(null);
358-
359-
when(keyGenerator.generateKey()).thenReturn(mockAesSecretKey);
360-
doReturn(rsaEncryptedAesKey).when(cryptoUtil).RSAEncrypt(testAesKeyBytes);
361-
PowerMockito.when(Base64.encode(rsaEncryptedAesKey, Base64.DEFAULT)).thenReturn(base64EncodedRsaKey.getBytes(StandardCharsets.UTF_8));
362-
363-
final byte[] aesKey = cryptoUtil.getAESKey();
364-
365-
Mockito.verify(keyGenerator).init(256);
366-
Mockito.verify(keyGenerator).generateKey();
367-
Mockito.verify(storage).store(KEY_ALIAS, base64EncodedRsaKey);
368-
assertThat(aesKey, is(notNullValue()));
369-
assertThat(aesKey, is(testAesKeyBytes));
370-
}
371-
372352
@Test
373353
public void shouldCreateAESKeyIfStoredOneIsEmpty() throws Exception {
374354
String emptyString = "";
@@ -403,16 +383,6 @@ public void shouldUseExistingAESKey() throws Exception {
403383
assertThat(aesKey, is(testAesKeyBytes));
404384
}
405385

406-
@Test
407-
public void shouldThrowOnNoSuchAlgorithmExceptionWhenCreatingAESKey() {
408-
Assert.assertThrows("The device is not compatible with the CryptoUtil class.", IncompatibleDeviceException.class, () -> {
409-
when(storage.retrieveString(KEY_ALIAS)).thenReturn(null);
410-
when(storage.retrieveString(OLD_KEY_ALIAS)).thenReturn(null);
411-
PowerMockito.when(KeyGenerator.getInstance(ALGORITHM_AES)).thenThrow(new NoSuchAlgorithmException());
412-
cryptoUtil.getAESKey();
413-
});
414-
}
415-
416386
@Test
417387
public void shouldRSAEncryptData() throws Exception {
418388
byte[] sampleInput = new byte[]{0, 1, 2, 3, 4, 5};
@@ -556,39 +526,6 @@ public void shouldAESDecryptData() throws Exception {
556526
assertThat(decrypted, is(testPlaintextData));
557527
}
558528

559-
@Test
560-
public void getAESKey_shouldMigrateAESKeyFromPKCS1ToOAEP() throws Exception {
561-
String base64EncodedPkcs1AesKey = "base64EncodedPkcs1AesKey";
562-
byte[] rsaPkcs1EncryptedAesKey = "RSA-PKCS1-encrypted-AES-key".getBytes(StandardCharsets.UTF_8);
563-
byte[] decryptedAesKey = new byte[32];
564-
Arrays.fill(decryptedAesKey, (byte) 1);
565-
566-
byte[] rsaOaepEncryptedMigratedAesKey = "new-oaep-encrypted-key".getBytes(StandardCharsets.UTF_8);
567-
String base64EncodedOaepMigratedAesKey = "bmV3LW9hZXAtZW5jcnlwdGVkLWtleQ==";
568-
569-
when(storage.retrieveString(KEY_ALIAS)).thenReturn(base64EncodedPkcs1AesKey);
570-
PowerMockito.when(Base64.decode(base64EncodedPkcs1AesKey, Base64.DEFAULT)).thenReturn(rsaPkcs1EncryptedAesKey);
571-
572-
doThrow(new CryptoException("OAEP failed", new BadPaddingException())).when(cryptoUtil).RSADecrypt(rsaPkcs1EncryptedAesKey);
573-
doReturn(mockRsaPrivateKeyEntry).when(cryptoUtil).getRSAKeyEntry();
574-
when(rsaPkcs1Cipher.doFinal(rsaPkcs1EncryptedAesKey)).thenReturn(decryptedAesKey);
575-
576-
doReturn(rsaOaepEncryptedMigratedAesKey).when(cryptoUtil).RSAEncrypt(decryptedAesKey);
577-
PowerMockito.when(Base64.encode(rsaOaepEncryptedMigratedAesKey, Base64.DEFAULT)).thenReturn(base64EncodedOaepMigratedAesKey.getBytes(StandardCharsets.UTF_8));
578-
579-
doNothing().when(cryptoUtil, "deleteRSAKeys");
580-
581-
byte[] resultAesKey = cryptoUtil.getAESKey();
582-
583-
assertThat(resultAesKey, is(decryptedAesKey));
584-
verify(cryptoUtil).RSADecrypt(rsaPkcs1EncryptedAesKey);
585-
verify(rsaPkcs1Cipher).init(Cipher.DECRYPT_MODE, mockRsaPrivateKey);
586-
verify(rsaPkcs1Cipher).doFinal(rsaPkcs1EncryptedAesKey);
587-
verifyPrivate(cryptoUtil).invoke("deleteRSAKeys");
588-
verify(cryptoUtil).RSAEncrypt(decryptedAesKey);
589-
verify(storage).store(KEY_ALIAS, base64EncodedOaepMigratedAesKey);
590-
}
591-
592529
private KeyPairGeneratorSpec.Builder newKeyPairGeneratorSpecBuilder(KeyPairGeneratorSpec expectedBuilderOutput) {
593530
KeyPairGeneratorSpec.Builder builder = PowerMockito.mock(KeyPairGeneratorSpec.Builder.class);
594531
when(builder.setAlias(anyString())).thenReturn(builder);

0 commit comments

Comments
 (0)