2017-03-20 2 views
5

Implémentation de AES256 sur iOS à l'aide de la fonction CCCrypt. Mais la sortie et la longueur du tampon de sortie est différente de celle d'Android.Chiffrement AES sur iOS et Android, la taille de la sortie et du tampon est différente

La classe de chiffrement d'Android produit des données de 48 octets, alors que dans iOS, nous obtenons des données de 80 octets.

Dans IOS en utilisant kCCAlgorithmAES, kCCOptionPKCS7Padding et dans android en utilisant AES/CBC/PKCS5Padding. Dans IOS IV est NULL et dans Android créant IV comme nouveau tableau de 16 octets.

Aidez-nous s'il vous plaît.

s'il vous plaît trouver l'entrée et le code pour la référence.

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSString *message = [NSString stringWithFormat:@"com.myapp.com|355004059196637|911111111111|11341e5e-9643-4559-bbb7-34d40555e96c"]; 
    NSString *key = [NSString stringWithFormat:@"4f28d5901b4b7b80d33fda76ca372c2a20bd1a6c2aad7fa215dc79d507330678"]; 
    NSString *shaEncryptMessage = [self sha256:message length:0]; 
    NSData *aesEncryptData = [self aesEncrypt:[shaEncryptMessage dataUsingEncoding:NSUTF8StringEncoding] key:key iv:nil]; 
    NSString *hMac = [aesEncryptData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; 
    NSLog(@"hMac = %@",hMac); 

    // IOS output : Can+oQR79D3/lsQGctzY/d2VBNZbWWtJxGI8iRIu80R2yTskn9gf2oKHaRESX73u 
    //     LpJHLx1Xr6iH11jFPlmqwW7mQz0xAW4uACNAMEoZ0kY= 
    // Android output : MiMDkdo5cGsPMj2qCnNobgp7dr5KMvBhGuKTonrqr1lCYte/kKegGMtI/4TPhUNI 
} 


- (NSString*) sha256:(NSString *)key length:(NSInteger) length{ 
    const char *s=[key cStringUsingEncoding:NSASCIIStringEncoding]; 
    NSData *keyData=[NSData dataWithBytes:s length:strlen(s)]; 

    uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0}; 
    CC_SHA256(keyData.bytes, (unsigned int)keyData.length, digest); 
    NSData *out=[NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; 
    NSString *hash=[out description]; 
    hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""]; 
    hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""]; 
    hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""]; 
    return hash; 
} 
- (NSData *)aesEncrypt:(NSData *)plainText key:(NSString *)key iv:(NSString *)iv { 
    char keyPointer[kCCKeySizeAES256+2],// room for terminator (unused) ref: https://devforums.apple.com/message/876053#876053 
    ivPointer[kCCBlockSizeAES128]; 
    BOOL patchNeeded; 
    bzero(keyPointer, sizeof(keyPointer)); // fill with zeroes for padding 
    //key = [[StringEncryption alloc] md5:key]; 
    key = [self stringFromHex:key]; 
    patchNeeded= ([key length] > kCCKeySizeAES256+1); 
    if(patchNeeded) 
    { 
     key = [key substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256) 
    } 

    [key getCString:keyPointer maxLength:sizeof(keyPointer) encoding:NSUTF8StringEncoding]; 
    [iv getCString:ivPointer maxLength:sizeof(ivPointer) encoding:NSUTF8StringEncoding]; 

    // if (patchNeeded) { 
    //  keyPointer[0] = '\0'; // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256 
    // } 

    NSUInteger dataLength = [plainText length]; 

    // For block ciphers, the output size will always be less than or equal to the input size plus the size of one block. 
    size_t buffSize = dataLength + kCCBlockSizeAES128; 
    void *buff = malloc(buffSize); 

    size_t numBytesEncrypted = 0; 



    CCCryptorStatus status = CCCrypt(kCCEncrypt, /* kCCEncrypt, etc. */ 
            kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */ 
            kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */ 
            keyPointer, kCCKeySizeAES256, /* key and its length */ 
            NULL, /* initialization vector - use random IV everytime */ 
            [plainText bytes], [plainText length], /* input */ 
            buff, buffSize,/* data RETURNED here */ 
            &numBytesEncrypted); 


    if (status == kCCSuccess) { 
     return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted]; 
    } 

    free(buff); 
    return nil; 
} 

- (NSString *) stringFromHex:(NSString *)str 
{ 
    NSMutableData *stringData = [[NSMutableData alloc] init]; 
    unsigned char whole_byte; 
    char byte_chars[3] = {'\0','\0','\0'}; 
    int i; 
    for (i=0; i < [str length]/2; i++) { 
     byte_chars[0] = [str characterAtIndex:i*2]; 
     byte_chars[1] = [str characterAtIndex:i*2+1]; 
     whole_byte = strtol(byte_chars, NULL, 16); 
     [stringData appendBytes:&whole_byte length:1]; 
    } 
    return [[NSString alloc] initWithData:stringData encoding:NSASCIIStringEncoding]; 
} 

S'il vous plaît trouver le code android aussi,

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    generateHMAC(); 
} 

String K0 = "4f28d5901b4b7b80d33fda76ca372c2a20bd1a6c2aad7fa215dc79d507330678"; 
String generatedString = "com.myapp.com|355004059196637|911111111111|11341e5e-9643-4559-bbb7-34d40555e96c"; 

private void generateHMAC() { 
    Log.d("Message of Hash", generatedString); 
    byte[] var14 = new byte[0]; 
    try { 
     var14 = SHA256(generatedString); 
     byte[] var15 = new byte[0]; 
     var15 = encrypt(var14, hexStringToByteArray(K0)); 
     String var4 = Base64.encodeToString(var15, 2); 
     Log.d("Existing K0", K0); 
     Log.d("HMAC", var4); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 


public byte[] SHA256(String paramString) throws Exception { 
    MessageDigest md = MessageDigest.getInstance("SHA-256"); 
    md.update(paramString.getBytes("UTF-8")); 
    byte[] digest = md.digest(); 
    return digest; 
} 

public byte[] encrypt(byte[] var1, byte[] var2) throws Exception { 
    SecretKeySpec var3 = new SecretKeySpec(var2, "AES"); 
    byte[] var4 = new byte[16]; 
    IvParameterSpec var5 = new IvParameterSpec(var4); 
    Cipher var6 = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    var6.init(1, var3, var5); 
    byte[] var7 = var6.doFinal(var1); 
    return var7; 
} 

public byte[] hexStringToByteArray(String var1) { 
    byte[] var2 = new byte[var1.length()/2]; 

    for (int var3 = 0; var3 < var2.length; ++var3) { 
     int var4 = var3 * 2; 
     int var5 = Integer.parseInt(var1.substring(var4, var4 + 2), 16); 
     var2[var3] = (byte) var5; 
    } 

    return var2; 
} 
+0

pls essayez https://github.com/alexeypro/EncryptDecrypt son AES256EncryptWithKey – Rivendell

+0

Pouvez-vous poster le code s'il vous plaît? – TheGreatContini

+0

Bien que cela ne réponde pas à votre question, sachez que bien qu'Apple vous dise que le vecteur d'initialisation (IV) est facultatif, le cryptage n'est pas sécurisé si vous ne le spécifiez pas et choisissez votre IV de manière imprévisible. Honte à Apple pour cette mauvaise API crypto. – TheGreatContini

Répondre

3

mises à jour après avoir fourni le code iOS:

  • Le aesEncryptData devrait être votre sortie. Débarrassez-vous du hmac, qui n'a rien à voir avec le cryptage AES (à la place, c'est pour l'intégrité du message).
  • La seule façon de faire correspondre votre code Android est si vous utilisez le même IV que le code Android utilise. Combien de temps est l'entrée

    :


Un peu plus tôt réponse? Fournir du code source et des exemples de données peut nous aider à résoudre le problème plus rapidement.

Sans les informations demandées, je n'ai pas votre réponse, mais j'ai quelques conseils qui pourraient vous aider à aller au fond de celui-ci:

  • Votre rembourrage est correct. PKCS5Padding en Java est wrongly named implémentation de PKCS # 7, donc il devrait être compatible avec kCCOptionPKCS7Padding d'Apple.
  • Apple by default uses CBC mode sous le capot si aucun mode n'est spécifié, de sorte que d'accord avec le code Android. Cela ne peut donc pas non plus être le problème.
  • Lorsque vous chiffrez, le texte chiffré sera un multiple de 16 octets (car AES a N = 16 octets de taille de bloc et selon defn de PKCS #7). Plus précisément:
    • Si l'entrée est un multiple de 16 octets, la sortie doit avoir exactement 16 octets de plus que l'entrée.
    • Si l'entrée n'est pas un multiple de 16 octets, la sortie doit être 16 * Plafond (Longueur d'entrée/16). Exemple: l'entrée de 47 octets doit être de 16 * Plafond (17/16) = 16 * 3 = sortie de 48 octets.
  • Il est possible que l'une des implémentations délivre la IV en tant que partie du texte chiffré. Si cela se produit, cela devrait être au début du texte chiffré. Vous devriez être capable de tester pour voir si cela se produit.(Faites-moi savoir si cela se passe s'il vous plaît)

Cela dit, quelque chose est bizarre et probablement mal implémenté, et nous avons besoin du code pour aller au fond de celui-ci. Il est absurde que le code Android aboutisse à 3 blocs de 16 alors que le code d'Apple se traduit par 5 blocs de 16.

Aussi, comme je l'ai dit plus haut, même si Apple vous dit que le IV est facultatif, ils signifient que c'est optionnel pour ce qui est de faire fonctionner le code. C'est not optional for security. Les IV sont requis et doivent être imprévisibles pour le mode de fonctionnement CBC, et ils ne devraient jamais être répétés. Si vous ignorez cela, vous fuyez des informations sur vos données, et dans certaines situations, un attaquant peut être en mesure de déchiffrer les données (padding oracle attaques).

+0

Merci @TheGreatContini, en ajoutant le code iOS et l'exemple d'entrée pour votre référence. S'il vous plaît, aidez à résoudre cela. – Pradip

+0

@Pradip vous avez HMAC-sha256 après l'AES, qui est un algorithme complètement différent. Prenez le HMAC, vous voulez seulement crypter et rien d'autre. Pour correspondre à Android, vous devrez utiliser le même IV qui est utilisé dans Android. Vous ne pouvez pas simplement remplacer nil et attendre que les données correspondent, car ce ne sera pas le cas. – TheGreatContini

+0

Veuillez trouver le code android mis à jour, SHA256 suivi par AES et sortie suivi par le codage base64 (comme notre logique requise). Je veux une logique similaire pour iOS comme dans Android. – Pradip