Chiffrement utilisant AES-128 sur Android et IPhone (résultat différent)
Je suis en train de chiffrer du texte à l'aide de l'algorithme AES sur le IPhone et Android plates-formes. Mon problème est que, même en utilisant le même chiffrement/déchiffrement de l'algorithme AES-128) et même les variables fixes (clé, IV, mode), j'obtiens des résultats différents sur les deux plates-formes. Je suis avec des exemples de code à partir de deux plates-formes, que j'utilise pour tester le chiffrement/déchiffrement. J'apprécierais un peu d'aide dans la détermination de ce que je fais de mal.
- Clé: “123456789abcdefg”
- IV: “1111111111111111”
- Texte: “HelloThere”
- Mode: “AES/SRC/NoPadding”
Android Code:
public class Crypto {
private final static String HEX = "0123456789ABCDEF";
public static String encrypt(String seed, String cleartext)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("CBC");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); //192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}
IPhone (Objective-C), Code:
- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {
NSData* secretKey = [Cipher md5:cipherKey];
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[secretKey bytes], kCCKeySizeAES128, iv, &cryptor);
if (status != kCCSuccess) {
return nil;
}
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);
void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
buf, bufsize, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
CCCryptorRelease(cryptor);
return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}
+ (NSData *) md5:(NSString *) stringToHash {
const char *src = [stringToHash UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(src, strlen(src), result);
return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}
Certains de mes références :
- http://code.google.com/p/aes-encryption-samples/wiki/HowToEncryptWithJava
- http://automagical.rationalmind.net/2009/02/12/aes-interoperability-between-net-and-iphone/
- AES interopérabilité entre .Net et iPhone?
source d'informationauteur UBA_MobileTeam
Vous devez vous connecter pour publier un commentaire.
Pour l'iPhone, j'ai utilisé AESCrypt-ObjCet pour Android, utilisez ce code:
Il me fait pas étonnant que vous obtenez des résultats différents.
Votre problème est que vous utilisez la mauvaise utilisation d'un SHA1PRNG pour la dérivation de clé. Autant que je sache, il n'existe pas de norme commune comment un SHA1PRNG de travail à l'interne. AFAIR même le J2SE et Bouncycaste mise en œuvre de la sortie des résultats différents en utilisant la même graine.
Donc votre mise en œuvre de votre
getRawKey(byte[] seed)
va générer une clé aléatoire. Si vous utilisez la clé de chiffrement que vous obtenez un résultat qui dépend de la clé. Tant que la clé est aléatoire, vous n'obtiendrez pas la même clé sur iOS et, par conséquent, vous obtenez un résultat différent.Si vous voulez une fonction de dérivation de clé d'utiliser une fonction PBKDF2 est presque entièrement normalisées concernant la dérivation de clé.
Sur Android, vous utilisez
getBytes()
. C'est une erreur car cela signifie que vous utilisez le jeu de caractères par défaut plutôt que de connu jeu de caractères. UtilisationgetBytes("UTF-8")
à la place de sorte que vous savez exactement ce octets que vous allez obtenir.Je ne sais pas l'équivalent pour Objective-C, mais ne comptez pas sur la valeur par défaut. Explicitement spécifier l'encodage UTF-8 lors de la conversion des chaînes d'octets. De cette façon, vous obtiendrez la même octets sur les deux côtés.
Je note aussi que vous êtes à l'aide de MD5 dans le code Objective-C, mais pas dans le code Android. Est-ce un choix délibéré?
Voir ma réponse pour mot de passe de chiffrement AES, depuis, vous utilisez votre "graines" comme mot de passe. (Il suffit de changer la longueur de clé de 256 128, si c'est ce que vous voulez.)
En essayant de générer la même clé par l'ensemencement d'une DRBG avec la même valeur n'est pas fiable.
Prochaine, vous n'êtes pas à l'aide de la SRC ou de la IV dans votre Android de chiffrement. Mon exemple montre comment le faire correctement. En passant, vous avez besoin de générer une nouvelle IV pour chaque message que vous chiffrer, comme mon exemple montre, et l'envoyer avec le texte chiffré. Sinon, il n'y a pas de point à l'aide de radio-canada.
Si vous voulez un exemple de code compatible avec Android et iPhone, regardez la RNCryptor bibliothèque pour iOS et le JNCryptor bibliothèque pour Java/Android.
Les deux projets sont open source et de partager un format de données commun. Dans ces bibliothèques, AES 256 bits est utilisé, cependant, il serait trivial de s'adapter le code, si nécessaire, à l'appui de 128-bit AES.
De par le a accepté de répondre, à la fois les bibliothèques utilisent PBKDF2.