這讓我難住 - 下面的代碼使用SpongyCastle的Android加密/解密 - 我試圖爲iOS實現跨平臺加密/解密。ios上的海綿堡壘加密等效物
下面的代碼(來自Android)使用提供的鹽和密碼來處理AES 128位CBC和PKCS7Padding,其中salt存儲在mysql數據庫中,密碼由最終用戶使用,以下代碼從kelhoer改編自這個答案。
我使用AES128bit的原因是AES256在iOS 4+中不可用,它是在iOS5 +中引入的,並且必須將腳趾插入到使用openssl
來生成派生密鑰和初始化向量(iv),這是冒險的據悉,蘋果拒絕與openssl庫靜態鏈接的應用程序。
由於該平臺基於iOS 4.2+,採用bundling and statically linking the openssl庫看起來頗爲過分,最好使用CommonCryptor庫。
這裏的Android版本與Spongycastle代碼到位:
private static void encrypt(InputStream fin,
OutputStream fout,
String password,
byte[] bSalt) {
try {
PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(
new SHA256Digest()
);
char[] passwordChars = password.toCharArray();
final byte[] pkcs12PasswordBytes =
PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
pGen.init(pkcs12PasswordBytes, bSalt, ITERATIONS);
CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
ParametersWithIV aesCBCParams =
(ParametersWithIV) pGen.generateDerivedParameters(128, 128);
aesCBC.init(true, aesCBCParams);
PaddedBufferedBlockCipher aesCipher =
new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
aesCipher.init(true, aesCBCParams);
byte[] buf = new byte[BUF_SIZE];
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = fin.read(buf)) >= 0) {
if (numRead == 1024) {
byte[] plainTemp = new byte[
aesCipher.getUpdateOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
final byte[] plain = new byte[offset];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
} else {
byte[] plainTemp = new byte[aesCipher.getOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
}
}
fout.close();
fin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void decrypt(InputStream fin,
OutputStream fout,
String password,
byte[] bSalt) {
try {
PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(
new SHA256Digest()
);
char[] passwordChars = password.toCharArray();
final byte[] pkcs12PasswordBytes =
PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
pGen.init(pkcs12PasswordBytes, bSalt, ITERATIONS);
CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
ParametersWithIV aesCBCParams =
(ParametersWithIV) pGen.generateDerivedParameters(128, 128);
aesCBC.init(false, aesCBCParams);
PaddedBufferedBlockCipher aesCipher =
new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
aesCipher.init(false, aesCBCParams);
byte[] buf = new byte[BUF_SIZE];
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = fin.read(buf)) >= 0) {
if (numRead == 1024) {
byte[] plainTemp = new byte[
aesCipher.getUpdateOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
// int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
} else {
byte[] plainTemp = new byte[
aesCipher.getOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
}
}
fout.close();
fin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
然而在iOS 4.2的(與XCode的工作),我想不出如何做等價,
這是我曾嘗試下目標C,與從Android側解密數據,存儲在MySQL數據庫的目標,測試了這一點:
+(NSData*) decrypt:(NSData*)cipherData
userPassword:(NSString*)argPassword
genSalt:(NSData*)argPtrSalt{
size_t szPlainBufLen = cipherData.length + (kCCBlockSizeAES128);
uint8_t *ptrPlainBuf = malloc(szPlainBufLen);
//
const unsigned char *ptrPasswd =
(const unsigned char*)[argPassword
cStringUsingEncoding:NSASCIIStringEncoding];
int ptrPasswdLen = strlen(ptrPasswd);
//
NSString *ptrSaltStr = [[NSString alloc]
initWithData:argPtrSalt
encoding:NSASCIIStringEncoding];
const unsigned char *ptrSalt =
(const unsigned char *)[ptrSaltStr UTF8String];
NSString *ptrCipherStr =
[[NSString alloc]initWithData:cipherData
encoding:NSASCIIStringEncoding];
unsigned char *ptrCipher = (unsigned char *)[ptrCipherStr UTF8String];
unsigned char key[kCCKeySizeAES128];
unsigned char iv[kCCKeySizeAES128];
//
//int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md,
//const unsigned char *salt, const unsigned char *data,
//int datal, int count, unsigned char *key,unsigned char *iv);
int i = EVP_BytesToKey(EVP_aes_128_cbc(),
EVP_sha256(),
ptrSalt,
ptrPasswd,
ptrPasswdLen,
PBKDF2_ITERATIONS,
key,
iv);
NSAssert(i == kCCKeySizeAES128,
@"Unable to generate key for AES");
//
size_t cipherLen = [cipherData length];
size_t outlength = 0;
//
CCCryptorStatus resultCCStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
key,
kCCBlockSizeAES128,
iv,
ptrCipher,
cipherLen,
ptrPlainBuf,
szPlainBufLen,
&outlength);
NSAssert(resultCCStatus == kCCSuccess,
@"Unable to perform PBE AES128bit decryption: %d", errno);
NSData *ns_dta_PlainData = nil;
if (resultCCStatus == kCCSuccess){
ns_dta_PlainData =
[NSData dataWithBytesNoCopy:ptrPlainBuf length:outlength];
}else{
return nil;
}
return ns_dta_PlainData;
}
有提供的數據和用戶的密碼,並從CCCrypt
獲得返回碼-4304
,表示解碼不成功並且錯誤。
我認爲編碼方案可能會拋棄CommonCryptor的解密路由,因此轉換爲NSASCIIStringEncoding
的冗長方式。
Salt與密碼數據一起存儲,長度爲32bytes。
我在這方面缺少什麼,要牢記在密碼學方面很薄弱。
我想你想要嘗試在iOS和Android之間使用不同的代碼庫時遇到麻煩,如果你想兼容。你爲什麼不找到一個C/C++ AES實現並將它編譯到兩個平臺的代碼庫中? – 2013-05-13 13:03:25