在理解兩個設備上的密碼/加密器時,我遇到了一個真正的問題。AES加密Android <-> iOS消息長度> 15字節的不同結果
1. 如果我們使用加密AES加密和字符串的charlength在iOS和Android上的消息不超過16大(例如「ABCDEFGHIJKLMNO」),我們使用相同的密鑰將其加密後得到了相同的結果/密碼。
2. 但是,如果需要較長的消息,我們得到的iOS和Android(例如「abcdefghijklmnop」)
我做了很多研究如何得到相同的params用於在兩個設備,並以不同的結果首先我認爲這是安全的。
這裏是加密我的密碼代碼:
public String encode(Context context, String password, String text)
throws NoPassGivenException, NoTextGivenException {
if (password.length() == 0 || password == null) {
throw new NoPassGivenException("Please give Password");
}
if (text.length() == 0 || text == null) {
throw new NoTextGivenException("Please give text");
}
try {
SecretKeySpec skeySpec = getKey(password);
byte[] clearText = text.getBytes("UTF8");
//IMPORTANT TO GET SAME RESULTS ON iOS and ANDROID
final byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Cipher is not thread safe
//EDITED AFTER RIGHT ANSWER FROM
//*** Cipher cipher = Cipher.getInstance("AES"); ***//
// TO
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
String encrypedValue = Base64.encodeToString(
cipher.doFinal(clearText), Base64.DEFAULT);
Log.d(TAG, "Encrypted: " + text + " -> " + encrypedValue);
return encrypedValue;
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return "";
}
public SecretKeySpec getKey(String password)
throws UnsupportedEncodingException {
int keyLength = 128;
byte[] keyBytes = new byte[keyLength/8];
// explicitly fill with zeros
Arrays.fill(keyBytes, (byte) 0x0);
// if password is shorter then key length, it will be zero-padded
// to key length
byte[] passwordBytes = password.getBytes("UTF-8");
int length = passwordBytes.length < keyBytes.length ? passwordBytes.length
: keyBytes.length;
System.arraycopy(passwordBytes, 0, keyBytes, 0, length);
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
return key;
}
這裏是從我的collegue iOS的掛件:
- (NSData *)AES128EncryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256,
// 16 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES128 + 1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// insert key in char array
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
// the encryption method, use always same attributes in android and iPhone (f.e. PKCS7Padding)
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr,
kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
我真的想了解什麼區別可能是,如何避免它。與更大的字符串比15個字符確切的測試給了我一個提示,但我不知道爲什麼:)
謝謝先進的傢伙!
檢查兩個系統上正在使用的填充。不同的填充會導致不同的輸出。不要依賴默認值,而是在兩側明確設置填充。你的第二個代碼片段顯式地設置PKCS7填充。在兩端使用它。 – rossum
呵呵,非常感謝,請給它一個答案'密碼cipher = Cipher.getInstance(「AES/CBC/PKCS7Padding」);' –
你的密鑰派生函數非常弱,而且密鑰可能是強制性的。您應該使用適當的密鑰派生函數,如PBKDF2或bcrypt。您也不應該使用靜態IV,因爲這會破壞CBC模式的某些安全屬性。 – ntoskrnl