Ошибка Android AES/GCM/NoPadding на определенной длине входных байтов?
я написал класс, который используется для шифрования произвольных данных.
это работает, как это:
Потому что AndroidKeyStore
сгенерированный ключ AES "потерян" после удаления приложения, у нас есть пара открытого/закрытого ключа, где открытый ключ включен в приложение.
Для целей fail save он используется для шифрования ключа AES, который дополняется перед каждым зашифрованным сообщением вдоль IV. Таким образом, мы можем восстановить ключ AES с помощью нашего закрытого ключа
в блоке тест я обнаружил, что он работает, для большинства входов. Странно, что на определенной длине массива байтов он терпит неудачу (я нашел т. е. 81920, 131073.)
Итак, вот код AESCrypto:
package com.mycompany.appname.crypto;
import android.content.Context;
import android.content.SharedPreferences;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.support.annotation.NonNull;
import android.util.Base64;
import android.util.Log;
import com.mycompany.appname.R;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesGcmCrypto implements Crypto{
public static final String TAG = AesGcmCrypto.class.getSimpleName();
private static final String KEY_ALIAS = "OI1lTI1ITLI1l0";
private static final String PREF_NAME = "CryptoPrefs";
private static final String KEY_ENCRYPTED_SECRET = "encryptedSecret";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String PUBLIC_KEY_ASSET = "public_key.der";
private static final int IV_SIZE = 12;
private static final String AES = KeyProperties.KEY_ALGORITHM_AES;
private static final String AES_BLOCK_MODE = KeyProperties.BLOCK_MODE_GCM;
private static final String AES_PADDING = KeyProperties.ENCRYPTION_PADDING_NONE;
private static final String AES_MODE = AES + "/" + AES_BLOCK_MODE + "/" + AES_PADDING;
//generate key, possible values 128 bit key (16), 192(24), 256(32)
private static final int AES_KEY_SIZE = 32;
private static final int AES_TAG_LEN = 128;
private static final String RSA = KeyProperties.KEY_ALGORITHM_RSA;
private static final String RSA_BLOCK_MODE = KeyProperties.BLOCK_MODE_ECB;
private static final String RSA_PADDING = KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1;
private static final String RSA_MODE = RSA + "/" + RSA_BLOCK_MODE + "/" + RSA_PADDING;
private static final String RSA_PROVIDER = "AndroidOpenSSL";
private final Context mContext;
private final SharedPreferences mPrefs;
private SecureRandom mSecureRandom;
private KeyStore mAndroidKeyStore;
private PublicKey mPublicKey;
private byte[] mEncryptedSecretKey;
public AesGcmCrypto(Context context) {
mContext = context;
mSecureRandom = new SecureRandom();
mPrefs = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
try {
mAndroidKeyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
mAndroidKeyStore.load(null);
} catch (KeyStoreException e) {
Log.wtf(TAG, mContext.getString(R.string.err_keystore_not_avail), e);
} catch (Exception e) {
Log.wtf(TAG, mContext.getString(R.string.err_keystore_not_loadable), e);
}
}
void reset() throws KeyStoreException {
mAndroidKeyStore.deleteEntry(KEY_ALIAS);
}
@Override
public byte[] encrypt(byte[] message) throws GeneralSecurityException{
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
GCMParameterSpec parameterSpec = cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
byte[] cryptedBytes = cipher.doFinal(message);
byte[] iv = parameterSpec.getIV();
byte[] encryptedSecretKey = getEncryptedSecretKey();
return ByteBuffer.allocate(iv.length + encryptedSecretKey.length + cryptedBytes.length)
.put(iv)
.put(encryptedSecretKey)
.put(cryptedBytes)
.array();
}
@Override
public byte[] decrypt(byte[] bytes) throws GeneralSecurityException{
ByteBuffer buffer = ByteBuffer.wrap(bytes);
byte[] iv = new byte[IV_SIZE];
buffer.get(iv);
//skip aes key bytes
byte[] irrelevant = new byte[AES_KEY_SIZE * 8];
buffer.get(irrelevant);
byte[] encryptedMessage = new byte[bytes.length - IV_SIZE - irrelevant.length];
buffer.get(encryptedMessage);
Cipher cipher = Cipher.getInstance(AES_MODE);
GCMParameterSpec parameterSpec = new GCMParameterSpec(AES_TAG_LEN, iv);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), parameterSpec);
byte[] decryptedMessage = cipher.doFinal(encryptedMessage);
return decryptedMessage;
}
public PublicKey getPublicKey() {
if (null == mPublicKey) {
mPublicKey = readPublicKey();
}
return mPublicKey;
}
public byte[] getEncryptedSecretKey() {
if (null == mEncryptedSecretKey){
mEncryptedSecretKey = Base64.decode(mPrefs.getString(KEY_ENCRYPTED_SECRET, null), Base64.NO_WRAP);
}
return mEncryptedSecretKey;
}
private void saveEncryptedSecretKey(byte[] encryptedSecretKey){
String base64EncryptedKey = Base64.encodeToString(encryptedSecretKey, Base64.NO_WRAP);
mPrefs.edit().putString(KEY_ENCRYPTED_SECRET, base64EncryptedKey).apply();
}
protected SecretKey getSecretKey(){
SecretKey secretKey = null;
try {
if (!mAndroidKeyStore.containsAlias(KEY_ALIAS)){
generateAndStoreSecureKey();
}
secretKey = (SecretKey) mAndroidKeyStore.getKey(KEY_ALIAS, null);
} catch (KeyStoreException e) {
Log.wtf(TAG, mContext.getString(R.string.err_keystore_aliasing_forbidden), e);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return secretKey;
}
private void generateAndStoreSecureKey()
throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, KeyStoreException, BadPaddingException, IllegalBlockSizeException {
//We cannot use AndroidKeyStore Generator, because it keeps its key-bytes inside the secure element
SecretKey secretKey = generateSecureRandomKey();
PublicKey publicKey = getPublicKey();
Cipher keyCipher = Cipher.getInstance(RSA_MODE, RSA_PROVIDER);
keyCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedSecretKeyBytes = keyCipher.doFinal(secretKey.getEncoded());
saveEncryptedSecretKey(encryptedSecretKeyBytes);
KeyProtection keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_VERIFY)
.setBlockModes(AES_BLOCK_MODE)
.setEncryptionPaddings(AES_PADDING)
.build();
mAndroidKeyStore.setEntry(KEY_ALIAS, new KeyStore.SecretKeyEntry(secretKey), keyProtection);
}
protected PublicKey readPublicKey() {
DataInputStream dis = null;
PublicKey key = null;
try {
dis = new DataInputStream(mContext.getResources().getAssets().open(PUBLIC_KEY_ASSET));
byte[] keyBytes = new byte[dis.available()];
dis.readFully(keyBytes);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory facotory = KeyFactory.getInstance(RSA);
key = facotory.generatePublic(spec);
} catch (Exception e) {
key = null;
} finally {
if (null != dis) {
try {
dis.close();
} catch (IOException e) {
Log.wtf(TAG, mContext.getString(R.string.err_cannot_close), e);
}
}
}
return key;
}
@NonNull
protected SecretKey generateSecureRandomKey() {
return new SecretKeySpec(generateSecureRandomBytes(AES_KEY_SIZE), AES);
}
@NonNull
protected byte[] generateSecureRandomBytes(int byteCount) {
byte[] keyBytes = new byte[byteCount];
mSecureRandom.nextBytes(keyBytes);
return keyBytes;
}
}
функция модульного теста выглядит следующим образом:
@Test
public void testCrypto() throws Exception{
AesGcmCrypto aesGcmCrypto = new AesGcmCrypto(InstrumentationRegistry.getTargetContext());
aesGcmCrypto.reset();
Random rand = new Random();
byte[] buffer = null;
for (int i = 1024 *20; i < 1024 * 200; i += 1024){
Log.i(TAG, "Testing " + i);
buffer = new byte[i];
rand.nextBytes(buffer);
byte[] encrypt = aesGcmCrypto.encrypt(buffer);
Assert.assertNotNull(encrypt);
decrypt = aesGcmCrypto.decrypt(encrypt);
Assert.assertNotNull(decrypt);
Assert.assertTrue(Arrays.equals(buffer, decrypt));
}
}
какие журналы:
09-13 00:06:16.034 17222-17238/com.mycompany.appname I/TestRunner: started: testCrypto(com.mycompany.appname.crypto.CryptoTest)
09-13 00:06:16.052 17222-17238/com.mycompany.appname I/CryptoTest: Testing 20480
09-13 00:06:16.205 17222-17238/com.mycompany.appname I/CryptoTest: Testing 21504
09-13 00:06:16.269 17222-17238/com.mycompany.appname I/CryptoTest: Testing 22528
09-13 00:06:16.337 17222-17238/com.mycompany.appname I/CryptoTest: Testing 23552
09-13 00:06:16.406 17222-17238/com.mycompany.appname I/CryptoTest: Testing 24576
09-13 00:06:16.469 17222-17238/com.mycompany.appname I/CryptoTest: Testing 25600
09-13 00:06:16.551 17222-17238/com.mycompany.appname I/CryptoTest: Testing 26624
09-13 00:06:16.632 17222-17238/com.mycompany.appname I/CryptoTest: Testing 27648
09-13 00:06:16.700 17222-17238/com.mycompany.appname I/CryptoTest: Testing 28672
09-13 00:06:16.765 17222-17238/com.mycompany.appname I/CryptoTest: Testing 29696
09-13 00:06:16.839 17222-17238/com.mycompany.appname I/CryptoTest: Testing 30720
09-13 00:06:16.906 17222-17238/com.mycompany.appname I/CryptoTest: Testing 31744
09-13 00:06:16.973 17222-17238/com.mycompany.appname I/CryptoTest: Testing 32768
09-13 00:06:17.043 17222-17238/com.mycompany.appname I/CryptoTest: Testing 33792
09-13 00:06:17.118 17222-17238/com.mycompany.appname I/CryptoTest: Testing 34816
09-13 00:06:17.191 17222-17238/com.mycompany.appname I/CryptoTest: Testing 35840
09-13 00:06:17.266 17222-17238/com.mycompany.appname I/CryptoTest: Testing 36864
09-13 00:06:17.341 17222-17238/com.mycompany.appname I/CryptoTest: Testing 37888
09-13 00:06:17.768 17222-17238/com.mycompany.appname I/CryptoTest: Testing 38912
09-13 00:06:17.850 17222-17238/com.mycompany.appname I/CryptoTest: Testing 39936
09-13 00:06:17.938 17222-17238/com.mycompany.appname I/CryptoTest: Testing 40960
09-13 00:06:18.020 17222-17238/com.mycompany.appname I/CryptoTest: Testing 41984
09-13 00:06:18.098 17222-17238/com.mycompany.appname I/CryptoTest: Testing 43008
09-13 00:06:18.171 17222-17238/com.mycompany.appname I/CryptoTest: Testing 44032
09-13 00:06:18.245 17222-17238/com.mycompany.appname I/CryptoTest: Testing 45056
09-13 00:06:18.672 17222-17238/com.mycompany.appname I/CryptoTest: Testing 46080
09-13 00:06:18.758 17222-17238/com.mycompany.appname I/CryptoTest: Testing 47104
09-13 00:06:18.838 17222-17238/com.mycompany.appname I/CryptoTest: Testing 48128
09-13 00:06:18.914 17222-17238/com.mycompany.appname I/CryptoTest: Testing 49152
09-13 00:06:18.992 17222-17238/com.mycompany.appname I/CryptoTest: Testing 50176
09-13 00:06:19.283 17222-17238/com.mycompany.appname I/CryptoTest: Testing 51200
09-13 00:06:19.434 17222-17238/com.mycompany.appname I/CryptoTest: Testing 52224
09-13 00:06:19.609 17222-17238/com.mycompany.appname I/CryptoTest: Testing 53248
09-13 00:06:19.722 17222-17238/com.mycompany.appname I/CryptoTest: Testing 54272
09-13 00:06:19.832 17222-17238/com.mycompany.appname I/CryptoTest: Testing 55296
09-13 00:06:20.021 17222-17238/com.mycompany.appname I/CryptoTest: Testing 56320
09-13 00:06:20.171 17222-17238/com.mycompany.appname I/CryptoTest: Testing 57344
09-13 00:06:20.335 17222-17238/com.mycompany.appname I/CryptoTest: Testing 58368
09-13 00:06:20.477 17222-17238/com.mycompany.appname I/CryptoTest: Testing 59392
09-13 00:06:20.658 17222-17238/com.mycompany.appname I/CryptoTest: Testing 60416
09-13 00:06:20.812 17222-17238/com.mycompany.appname I/CryptoTest: Testing 61440
09-13 00:06:21.001 17222-17238/com.mycompany.appname I/CryptoTest: Testing 62464
09-13 00:06:21.108 17222-17238/com.mycompany.appname I/CryptoTest: Testing 63488
09-13 00:06:21.267 17222-17238/com.mycompany.appname I/CryptoTest: Testing 64512
09-13 00:06:21.414 17222-17238/com.mycompany.appname I/CryptoTest: Testing 65536
09-13 00:06:21.570 17222-17238/com.mycompany.appname I/CryptoTest: Testing 66560
09-13 00:06:21.731 17222-17238/com.mycompany.appname I/CryptoTest: Testing 67584
09-13 00:06:21.902 17222-17238/com.mycompany.appname I/CryptoTest: Testing 68608
09-13 00:06:22.083 17222-17238/com.mycompany.appname I/CryptoTest: Testing 69632
09-13 00:06:22.255 17222-17238/com.mycompany.appname I/CryptoTest: Testing 70656
09-13 00:06:22.478 17222-17238/com.mycompany.appname I/CryptoTest: Testing 71680
09-13 00:06:22.638 17222-17238/com.mycompany.appname I/CryptoTest: Testing 72704
09-13 00:06:22.840 17222-17238/com.mycompany.appname I/CryptoTest: Testing 73728
09-13 00:06:23.146 17222-17238/com.mycompany.appname I/CryptoTest: Testing 74752
09-13 00:06:23.345 17222-17238/com.mycompany.appname I/CryptoTest: Testing 75776
09-13 00:06:23.647 17222-17238/com.mycompany.appname I/CryptoTest: Testing 76800
09-13 00:06:23.820 17222-17238/com.mycompany.appname I/CryptoTest: Testing 77824
09-13 00:06:23.995 17222-17238/com.mycompany.appname I/CryptoTest: Testing 78848
09-13 00:06:24.200 17222-17238/com.mycompany.appname I/CryptoTest: Testing 79872
09-13 00:06:24.394 17222-17238/com.mycompany.appname I/CryptoTest: Testing 80896
09-13 00:06:24.645 17222-17238/com.mycompany.appname I/CryptoTest: Testing 81920
09-13 00:06:24.849 17222-17238/com.mycompany.appname I/TestRunner: failed: testCrypto3(com.mycompany.appname.crypto.CryptoTest)
----- begin exception -----
09-13 00:06:24.858 17222-17238/com.mycompany.appname I/TestRunner: junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:48)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertTrue(Assert.java:27)
at com.mycompany.appname.crypto.CryptoTest.testCrypto3(CryptoTest.java:72)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
----- end exception -----
09-13 00:06:24.875 17222-17238/com.mycompany.appname I/TestRunner: finished: testCrypto(com.mycompany.appname.crypto.CryptoTest)
теперь большой вопрос: Есть ли ошибка в моей реализации или это ошибка фреймворка, о которой следует сообщить, чтобы предотвратить невозможность де-и шифрования данных определенная длина байта?
BTW: Я исправил проблему, используя буферизованный de и шифрование, как это (метод exchange в AesGcmCrypto)
private static final int CIPHER_CHUCK_SIZE = 64 * 1024;
@Override
public byte[] encrypt(byte[] message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
GCMParameterSpec parameterSpec = cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
int outLen = cipher.getOutputSize(message.length);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
for (int i = 0; i < message.length; i += CIPHER_CHUCK_SIZE) {
int len = Math.min(CIPHER_CHUCK_SIZE, message.length - i);
bout.write(cipher.update(message, i, len));
}
bout.write(cipher.doFinal());
} catch (IOException e) {
e.printStackTrace();
throw new GeneralSecurityException(e);
}
byte[] cryptedBytes = bout.toByteArray();
if (outLen != cryptedBytes.length)
throw new GeneralSecurityException("cryptedBytes too small");
byte[] iv = parameterSpec.getIV();
byte[] encryptedSecretKey = getEncryptedSecretKey();
return ByteBuffer.allocate(iv.length + encryptedSecretKey.length + cryptedBytes.length)
.put(iv)
.put(encryptedSecretKey)
.put(cryptedBytes)
.array();
}
@Override
public byte[] decrypt(byte[] bytes) throws GeneralSecurityException {
ByteBuffer buffer = ByteBuffer.wrap(bytes);
byte[] iv = new byte[IV_SIZE];
buffer.get(iv);
//skip aes key bytes
byte[] irrelevant = new byte[AES_KEY_SIZE * 8];
buffer.get(irrelevant);
byte[] encryptedMessage = new byte[bytes.length - IV_SIZE - irrelevant.length];
buffer.get(encryptedMessage);
Cipher cipher = Cipher.getInstance(AES_MODE);
GCMParameterSpec parameterSpec = new GCMParameterSpec(AES_TAG_LEN, iv);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), parameterSpec);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
for (int i = 0; i < encryptedMessage.length; i += CIPHER_CHUCK_SIZE) {
int len = Math.min(CIPHER_CHUCK_SIZE, encryptedMessage.length - i);
cipher.update(encryptedMessage, i, len);
}
bout.write(cipher.doFinal());
} catch (IOException e) {
e.printStackTrace();
throw new GeneralSecurityException(e);
}
byte[] decryptedMessage = bout.toByteArray();
return decryptedMessage;
}
из-за этого исправить я твердо верю, что это должна быть ошибка фреймворка. если бы кто-то с передовыми знаниями шифрования мог просветить меня, я был бы очень рад.
1 ответов
Я не нашел корень проблемы. Все что я могу сказать, что это, кажется, не ошибка!
я упростил де-и шифрование следующим образом:
package com.dermalog.votercheck.crypto;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
public class SimpleCrypto {
private final SecretKey mSecretKey;
public SimpleCrypto(SecretKey secretKey){
mSecretKey = secretKey;
}
public byte[] encrypt(byte[] data) throws GeneralSecurityException {
Cipher aes = Cipher.getInstance("AES/GCM/NoPadding");
aes.init(Cipher.ENCRYPT_MODE, mSecretKey);
GCMParameterSpec parameterSpec = aes.getParameters().getParameterSpec(GCMParameterSpec.class);
byte[] encrypted = aes.doFinal(data);
if (encrypted.length != aes.getOutputSize(data.length)){
throw new GeneralSecurityException("Encrypted Output Size does not match cipher.getOutputSize");
}
return ByteBuffer.allocate(12 + encrypted.length).put(parameterSpec.getIV()).put(encrypted).array();
}
public byte[] decrypt(byte[] encryptedData) throws GeneralSecurityException{
ByteBuffer buffer = ByteBuffer.wrap(encryptedData);
byte[] iv = new byte[12];
buffer.get(iv);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
Cipher aes = Cipher.getInstance("AES/GCM/NoPadding");
aes.init(Cipher.DECRYPT_MODE, mSecretKey, parameterSpec);
byte[] encryptedMessage = new byte[encryptedData.length - 12];
buffer.get(encryptedMessage);
return aes.doFinal(encryptedMessage);
}
}
и протестировал его (успешно) следующим образом:
@Test
public void testSimpleCrypto() throws GeneralSecurityException {
SecureRandom secureRandom = new SecureRandom();
Random random = new Random();
byte[] keyBytes = new byte[32];
secureRandom.nextBytes(keyBytes);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
SimpleCrypto crypto = new SimpleCrypto(secretKey);
String test = "SecretData";
byte[] encrypted = crypto.encrypt(test.getBytes(StandardCharsets.UTF_8));
byte[] decrypted = crypto.decrypt(encrypted);
Assert.assertEquals(new String(decrypted, StandardCharsets.UTF_8), test);
byte[] randomData = new byte[81920];
random.nextBytes(randomData);
encrypted = crypto.encrypt(randomData);
decrypted = crypto.decrypt(encrypted);
Assert.assertArrayEquals(randomData, decrypted);
randomData = new byte[131073];
random.nextBytes(randomData);
encrypted = crypto.encrypt(randomData);
decrypted = crypto.decrypt(encrypted);
Assert.assertArrayEquals(randomData, decrypted);
for (int i = 1024 * 20; i < 1024 * 300; i+= 1024) {
randomData = new byte[i];
random.nextBytes(randomData);
encrypted = crypto.encrypt(randomData);
decrypted = crypto.decrypt(encrypted);
Assert.assertArrayEquals(randomData, decrypted);
}
}
таким образом, ошибка должна быть на моей стороне реализации (хотя я понятия не имею, почему исправление, которое я реализовал, работает)
просто хотел написать продолжение.
BTW: если кто-то хочет захватить награду просто ответ. Было бы слишком плохо, если бы моя репутация была потеряна зря ^^