gpt4 book ai didi

android - 在 Android 和 iPhone 中使用 AES 256 加密(结果不同)

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:32:35 25 4
gpt4 key购买 nike

我正在尝试通过引用IOS实现在Android平台上实现客户端加密/解密。我正在纠结Android和IOS平台的加密和解密即使使用相同的算法也是不同的。比方说,当 Android 设备加密并上传文件到服务器时,IOS 设备无法正确下载和解密它。

我正在使用的算法

  1. 使用用户提供的密码加密文件 key 。我们首先使用 PBKDF2 算法(SHA256 的 1000 次迭代)从密码中导出 key /iv 对,然后使用 AES 256/CBC 加密文件 key 。结果称为“加密文件 key ”。这个加密的文件 key 将被发送到服务器并存储在服务器上。当您需要访问数据时,您可以从加密的文件 key 中解密出文件 key 。
  2. 所有文件数据均使用 AES 256/CBC 文件 key 加密。我们使用 PBKDF2 算法(SHA256 的 1000 次迭代)从文件 key 派生 key /iv 对。
  3. 将导出的 key /iv 对存储在本地并使用它们来加密文件。数据加密后上传到服务器。下载文件时解密文件也是一样。

安卓代码

    private static final String TAG = Crypto.class.getSimpleName();

private static final String CIPHER_ALGORITHM = "AES/CBC/NoPadding";

private static int KEY_LENGTH = 32;
private static int KEY_LENGTH_SHORT = 16;
// minimum values recommended by PKCS#5, increase as necessary
private static int ITERATION_COUNT = 1000;
// Should generate random salt for each repo
private static byte[] salt = {(byte) 0xda, (byte) 0x90, (byte) 0x45, (byte) 0xc3, (byte) 0x06, (byte) 0xc7, (byte) 0xcc, (byte) 0x26};

private Crypto() {
}

/**
* decrypt repo encKey
*
* @param password
* @param randomKey
* @param version
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public static String deriveKeyPbkdf2(String password, String randomKey, int version) throws UnsupportedEncodingException, NoSuchAlgorithmException {
if (TextUtils.isEmpty(password) || TextUtils.isEmpty(randomKey)) {
return null;
}

PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
gen.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password.toCharArray()), salt, ITERATION_COUNT);
byte[] keyBytes;

if (version == 2) {
keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH * 8)).getKey();
} else
keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH_SHORT * 8)).getKey();

SecretKey realKey = new SecretKeySpec(keyBytes, "AES");

final byte[] iv = deriveIVPbkdf2(realKey.getEncoded());

return seafileDecrypt(fromHex(randomKey), realKey, iv);
}

public static byte[] deriveIVPbkdf2(byte[] key) throws UnsupportedEncodingException {
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
gen.init(key, salt, 10);
return ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH_SHORT * 8)).getKey();
}

/**
* All file data is encrypted by the file key with AES 256/CBC.
*
* We use PBKDF2 algorithm (1000 iterations of SHA256) to derive key/iv pair from the file key.
* After encryption, the data is uploaded to the server.
*
* @param plaintext
* @param key
* @return
*/
private static byte[] seafileEncrypt(byte[] plaintext, SecretKey key, byte[] iv) {
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);

return cipher.doFinal(plaintext);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Log.e(TAG, "NoSuchAlgorithmException " + e.getMessage());
return null;
} catch (InvalidKeyException e) {
e.printStackTrace();
Log.e(TAG, "InvalidKeyException " + e.getMessage());
return null;
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
Log.e(TAG, "InvalidAlgorithmParameterException " + e.getMessage());
return null;
} catch (NoSuchPaddingException e) {
e.printStackTrace();
Log.e(TAG, "NoSuchPaddingException " + e.getMessage());
return null;
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
Log.e(TAG, "IllegalBlockSizeException " + e.getMessage());
return null;
} catch (BadPaddingException e) {
e.printStackTrace();
Log.e(TAG, "BadPaddingException " + e.getMessage());
return null;
}
}

/**
* All file data is encrypted by the file key with AES 256/CBC.
*
* We use PBKDF2 algorithm (1000 iterations of SHA256) to derive key/iv pair from the file key.
* After encryption, the data is uploaded to the server.
*
* @param plaintext
* @param key
* @return
*/
public static byte[] encrypt(byte[] plaintext, String key, byte[] iv, int version) throws NoSuchAlgorithmException {
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
gen.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(key.toCharArray()), salt, ITERATION_COUNT);
byte[] keyBytes;

if (version == 2) {
keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH * 8)).getKey();
} else
keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH_SHORT * 8)).getKey();

SecretKey realKey = new SecretKeySpec(keyBytes, "AES");
return seafileEncrypt(plaintext, realKey , iv);
}

IOS代码

+ (int)deriveKey:(const char *)data_in inlen:(int)in_len version:(int)version key:(unsigned char *)key iv:(unsigned char *)iv
{
unsigned char salt[8] = { 0xda, 0x90, 0x45, 0xc3, 0x06, 0xc7, 0xcc, 0x26 };
if (version == 2) {
PKCS5_PBKDF2_HMAC (data_in, in_len,
salt, sizeof(salt),
1000,
EVP_sha256(),
32, key);
PKCS5_PBKDF2_HMAC ((char *)key, 32,
salt, sizeof(salt),
10,
EVP_sha256(),
16, iv);
return 0;
} else if (version == 1)
return EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */
EVP_sha1(), /* message digest */
salt, /* salt */
(unsigned char*)data_in,
in_len,
1 << 19, /* iteration times */
key, /* the derived key */
iv); /* IV, initial vector */
else
return EVP_BytesToKey (EVP_aes_128_ecb(), /* cipher mode */
EVP_sha1(), /* message digest */
NULL, /* salt */
(unsigned char*)data_in,
in_len,
3, /* iteration times */
key, /* the derived key */
iv); /* IV, initial vector */
}

+(int)seafileEncrypt:(char **)data_out outlen:(int *)out_len datain:(const char *)data_in inlen:(const int)in_len version:(int)version key:(uint8_t *)key iv:(uint8_t *)iv
{
int ret, blks;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init (&ctx);
if (version == 2)
ret = EVP_EncryptInit_ex (&ctx,
EVP_aes_256_cbc(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
else if (version == 1)
ret = EVP_EncryptInit_ex (&ctx,
EVP_aes_128_cbc(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
else
ret = EVP_EncryptInit_ex (&ctx,
EVP_aes_128_ecb(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
if (ret == DEC_FAILURE)
return -1;

blks = (in_len / BLK_SIZE) + 1;
*data_out = (char *)malloc (blks * BLK_SIZE);
if (*data_out == NULL) {
Debug ("failed to allocate the output buffer.\n");
goto enc_error;
}
int update_len, final_len;

/* Do the encryption. */
ret = EVP_EncryptUpdate (&ctx,
(unsigned char*)*data_out,
&update_len,
(unsigned char*)data_in,
in_len);

if (ret == ENC_FAILURE)
goto enc_error;


/* Finish the possible partial block. */
ret = EVP_EncryptFinal_ex (&ctx,
(unsigned char*)*data_out + update_len,
&final_len);

*out_len = update_len + final_len;

/* out_len should be equal to the allocated buffer size. */
if (ret == ENC_FAILURE || *out_len != (blks * BLK_SIZE))
goto enc_error;

EVP_CIPHER_CTX_cleanup (&ctx);

return 0;

enc_error:
EVP_CIPHER_CTX_cleanup (&ctx);
*out_len = -1;

if (*data_out != NULL)
free (*data_out);

*data_out = NULL;

return -1;
}

+ (void)generateKey:(NSString *)password version:(int)version encKey:(NSString *)encKey key:(uint8_t *)key iv:(uint8_t *)iv
{
unsigned char key0[32], iv0[16];
char passwordPtr[256] = {0}; // room for terminator (unused)
[password getCString:passwordPtr maxLength:sizeof(passwordPtr) encoding:NSUTF8StringEncoding];
if (version < 2) {
[NSData deriveKey:passwordPtr inlen:(int)password.length version:version key:key iv:iv];
return;
}
[NSData deriveKey:passwordPtr inlen:(int)password.length version:version key:key0 iv:iv0];
char enc_random_key[48], dec_random_key[48];
int outlen;
hex_to_rawdata(encKey.UTF8String, enc_random_key, 48);
[NSData seafileDecrypt:dec_random_key outlen:&outlen datain:(char *)enc_random_key inlen:48 version:2 key:key0 iv:iv0];
[NSData deriveKey:dec_random_key inlen:32 version:2 key:key iv:iv];
}

- (NSData *)encrypt:(NSString *)password encKey:(NSString *)encKey version:(int)version
{
uint8_t key[kCCKeySizeAES256+1] = {0}, iv[kCCKeySizeAES128+1];
[NSData generateKey:password version:version encKey:encKey key:key iv:iv];
char *data_out;
int outlen;
int ret = [NSData seafileEncrypt:&data_out outlen:&outlen datain:self.bytes inlen:(int)self.length version:version key:key iv:iv];
if (ret < 0) return nil;
return [NSData dataWithBytesNoCopy:data_out length:outlen];
}

这是一个完整的项目,供任何认为有用的人使用。

  1. Support client side encryption #487
  2. How does an encrypted library work?

最佳答案

你好,我也遇到了同样的问题。

我发现有两件事导致我的代码不匹配: 1. ios 和 android 加密算法不一样(我在 ios 中请求了 PKCS7Padding 算法,我在 android 中尝试了 NoPadding 和 AES/CBC/PKCS5Padding 算法。 2. ios生成的key和android不一样。

请看我的工作代码在 ios 和 android 中都给出了相同的输出:

iOS:

- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
return [data base64EncodedStringWithOptions:kNilOptions];
}
- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
if ([ciphertext isKindOfClass:[NSString class]]) {

NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
return nil;
}

Android:(我们修改了 aes w.r.t iOS 默认方法)

private static String Key = "your key"; 
public static String encryptString(String stringToEncode) throws NullPointerException {

try {
SecretKeySpec skeySpec = getKey(Key);
byte[] clearText = stringToEncode.getBytes("UTF8");
final byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
String encrypedValue = Base64.encodeToString(cipher.doFinal(clearText), Base64.DEFAULT);
return encrypedValue;

} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static String encryptString(String stringToEncode) throws NullPointerException {

try {
SecretKeySpec skeySpec = getKey(Key);
byte[] clearText = stringToEncode.getBytes("UTF8");
final byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] cipherData = cipher.doFinal(Base64.decode(stringToEncode.getBytes("UTF-8"), Base64.DEFAULT));
String decoded = new String(cipherData, "UTF-8");
return decoded;

} catch (Exception e) {
e.printStackTrace();
}
return "";
}


private static SecretKeySpec getKey(String password) throws UnsupportedEncodingException {
int keyLength = 256;
byte[] keyBytes = new byte[keyLength / 8];
Arrays.fill(keyBytes, (byte) 0x0);
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;
}

希望对大家有帮助谢谢

关于android - 在 Android 和 iPhone 中使用 AES 256 加密(结果不同),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36589644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com