2015-11-19 1 views
-1

J'essaye de mettre à niveau mon application actuelle dans iOS 8, pour m'adapter au nouveau cryptage SHA256 de Redsys/Sermpa.3DES crypter le résultat en PHP, JAVA et .NET produit un résultat différent de 3DES iOS

Mais j'ai des problèmes dans le cryptage des données. En PHP, Java et .NET, j'obtiens un résultat, complètement différent d'iOS.

Je pense que le problème doit être dans le 3DES IOS CCCrypt.

Le code PHP, JAVA et .NET est une bibliothèque, je ne peux pas modifier cette bibliothèque.

Je dois faire le résultat du cryptage dans iOS, est identique à crypter le bon résultat en PHP, JAVA et .NET.

Bibliothèque du code Java:

String secretCodeString = "Mk9m98IfEblmPfrpsawt7BmxObt98Jev"; 
    String Ds_Merchant_Order = "1442772645"; 
    String Ds_MerchantParameters = "eyJEU19NRVJDSEFOVF9BTU9VTlQiOiIxNDUiLCJEU19NRVJDSEFOVF9PUkRFUiI6IjE0NDI3NzI2NDUiLCJEU19NRVJDSEFOVF9NRVJDSEFOVENPREUiOiI5OTkwMDg4ODEiLCJEU19NRVJDSEFOVF9DVVJSRU5DWSI6Ijk3OCIsIkRTX01FUkNIQU5UX1RSQU5TQUNUSU9OVFlQRSI6IjAiLCJEU19NRVJDSEFOVF9URVJNSU5BTCI6Ijg3MSIsIkRTX01FUkNIQU5UX01FUkNIQU5UVVJMIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX05vdGlmLnBocCIsIkRTX01FUkNIQU5UX1VSTE9LIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCIsIkRTX01FUkNIQU5UX1VSTEtPIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCJ9"; 

    byte [] secretCode = decodeB64(secretCodeString.getBytes("UTF-8")); 
    String secretKc = toHexadecimal(secretCode, secretCode.length); 
    byte [] Ds_Merchant_Order_encrypt3DES = encrypt_3DES(secretKc, Ds_Merchant_Order); 
    byte [] hash = mac256(Ds_MerchantParameters, Ds_Merchant_Order_encrypt3DES); 
    byte [] res = encodeB64UrlSafe(hash); 
    String Ds_Signature = new String(res, "UTF-8"); 
    //Ds_Signature: hueCwD/cbvrCi+9IDY86WteMpXulIl0IDNXNlYgcZHM= 


public byte [] encrypt_3DES(final String claveHex, final String datos) { 
     byte [] ciphertext = null; 
     try { 
      DESedeKeySpec desKeySpec = new DESedeKeySpec(toByteArray(claveHex)); 
      SecretKey desKey = new SecretKeySpec(desKeySpec.getKey(), "DESede"); 
      Cipher desCipher = Cipher.getInstance("DESede/CBC/NoPadding"); 
      byte [] IV = {0, 0, 0, 0, 0, 0, 0, 0}; 

      desCipher.init(Cipher.ENCRYPT_MODE, desKey, new IvParameterSpec(IV)); 

      int numeroCerosNecesarios = 8 - (datos.length() % 8); 
      if (numeroCerosNecesarios == 8) { 
       numeroCerosNecesarios = 0; 
      } 
      ByteArrayOutputStream array = new ByteArrayOutputStream(); 
      array.write(datos.getBytes("UTF-8"), 0, datos.length()); 
      for (int i = 0; i < numeroCerosNecesarios; i++) { 
       array.write(0); 
      } 
      byte [] cleartext = array.toByteArray(); 

      ciphertext = desCipher.doFinal(cleartext); 
     } catch (Exception e) { 
      e.printStackTrace(System.err); 
     } 
     return ciphertext; 
    } 

bibliothèque PHP Code:

$Ds_Merchant_Order = "1442772645"; 
    $Ds_MerchantParameters = "eyJEU19NRVJDSEFOVF9BTU9VTlQiOiIxNDUiLCJEU19NRVJDSEFOVF9PUkRFUiI6IjE0NDI3NzI2NDUiLCJEU19NRVJDSEFOVF9NRVJDSEFOVENPREUiOiI5OTkwMDg4ODEiLCJEU19NRVJDSEFOVF9DVVJSRU5DWSI6Ijk3OCIsIkRTX01FUkNIQU5UX1RSQU5TQUNUSU9OVFlQRSI6IjAiLCJEU19NRVJDSEFOVF9URVJNSU5BTCI6Ijg3MSIsIkRTX01FUkNIQU5UX01FUkNIQU5UVVJMIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX05vdGlmLnBocCIsIkRTX01FUkNIQU5UX1VSTE9LIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCIsIkRTX01FUkNIQU5UX1VSTEtPIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCJ9"; 
    $secretCode = "Mk9m98IfEblmPfrpsawt7BmxObt98Jev"; 

    $secretCode = base64_decode($secretCode); 
    $bytes = array(0,0,0,0,0,0,0,0); 
    $iv = implode(array_map("chr", $bytes)); //PHP 4 >= 4.0.2 
    $Ds_Merchant_Order_encrypt3DES = mcrypt_encrypt(MCRYPT_3DES, $secretCode, $Ds_Merchant_Order, MCRYPT_MODE_CBC, $iv); 
    $hash = hash_hmac('sha256', $Ds_MerchantParameters, $Ds_Merchant_Order_encrypt3DES, true); 
    $Ds_Signature = $this->encodeBase64($hash); 
    //Ds_Signature: hueCwD/cbvrCi+9IDY86WteMpXulIl0IDNXNlYgcZHM= 

Bibliothèque code .NET:

byte[] secretCode = Base64Decode("Mk9m98IfEblmPfrpsawt7BmxObt98Jev"); 

    string Ds_MerchantParameters = "eyJEU19NRVJDSEFOVF9BTU9VTlQiOiIxNDUiLCJEU19NRVJDSEFOVF9PUkRFUiI6IjE0NDI3NzI2NDUiLCJEU19NRVJDSEFOVF9NRVJDSEFOVENPREUiOiI5OTkwMDg4ODEiLCJEU19NRVJDSEFOVF9DVVJSRU5DWSI6Ijk3OCIsIkRTX01FUkNIQU5UX1RSQU5TQUNUSU9OVFlQRSI6IjAiLCJEU19NRVJDSEFOVF9URVJNSU5BTCI6Ijg3MSIsIkRTX01FUkNIQU5UX01FUkNIQU5UVVJMIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX05vdGlmLnBocCIsIkRTX01FUkNIQU5UX1VSTE9LIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCIsIkRTX01FUkNIQU5UX1VSTEtPIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCJ9" 
    string Ds_Merchant_Order = "1442772645"; 

    // Calculate derivated key by encrypting with 3DES the "DS_MERCHANT_ORDER" with decoded key 
    byte[] Ds_Merchant_Order_encrypt3DES = cryp.Encrypt3DES(Ds_Merchant_Order, secretCode); 

    // Calculate HMAC SHA256 with Encoded base64 JSON string using derivated key calculated previously 
    byte[] hash = cryp.GetHMACSHA256(Ds_MerchantParameters, Ds_Merchant_Order_encrypt3DES); 

    // Encode byte[] res to Base64 String 
    string Ds_Signature = Base64Encode2(hash); 
    //Ds_Signature: hueCwD/cbvrCi+9IDY86WteMpXulIl0IDNXNlYgcZHM= 

    public byte[] Encrypt3DES(string plainText, byte[] key) { 
      byte[] toEncryptArray = Encoding.UTF8.GetBytes(plainText); 
      TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider(); 

      try { 
       /// SALT used in 3DES encryptation process. 
       byte[] SALT = new byte[8] {0,0,0,0,0,0,0,0}; 

       // Block size 64 bit (8 bytes) 
       tdes.BlockSize = 64; 

       // Key Size 192 bit (24 bytes) 
       tdes.KeySize = 192; 
       tdes.Mode = CipherMode.CBC; 
       tdes.Padding = PaddingMode.Zeros; 

       tdes.IV = SALT; 
       tdes.Key = key; 

       var cTransform = tdes.CreateEncryptor(); 

       //transform the specified region of bytes array to resultArray 
       byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 

       //Release resources held by TripleDes Encryptor 
       tdes.Clear(); 

       return resultArray; 

      } // Error in Cryptographic method 
      catch (CryptographicException ex) { 
       throw new CryptographicException(ex.Message); 
      } 
     } 

********************** ------------ **************** ****** ------------ **********************

Mon code Objective-C :

NSString *Ds_Merchant_Order = @"1442772645"; 
NSString *Ds_MerchantParameters = @"eyJEU19NRVJDSEFOVF9BTU9VTlQiOiIxNDUiLCJEU19NRVJDSEFOVF9PUkRFUiI6IjE0NDI3NzI2NDUiLCJEU19NRVJDSEFOVF9NRVJDSEFOVENPREUiOiI5OTkwMDg4ODEiLCJEU19NRVJDSEFOVF9DVVJSRU5DWSI6Ijk3OCIsIkRTX01FUkNIQU5UX1RSQU5TQUNUSU9OVFlQRSI6IjAiLCJEU19NRVJDSEFOVF9URVJNSU5BTCI6Ijg3MSIsIkRTX01FUkNIQU5UX01FUkNIQU5UVVJMIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX05vdGlmLnBocCIsIkRTX01FUkNIQU5UX1VSTE9LIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCIsIkRTX01FUkNIQU5UX1VSTEtPIjoiaHR0cHM6XC9cL2VqZW1wbG9cL2VqZW1wbG9fVVJMX09LX0tPLnBocCJ9"; 

NSString *clave = @"Mk9m98IfEblmPfrpsawt7BmxObt98Jev"; 
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:clave options:0]; 
NSString *secretCode = [self hexadecimalString:decodedData]; 

NSData *Ds_Merchant_Order_encrypt3DES = [self encrypt3DES:Ds_Merchant_Order key:secretCode]; 

NSData *hash = [self hmac256ForKeyAndData:Ds_MerchantParameters withKey:Ds_Merchant_Order_encrypt3DES]; 

NSString *Ds_Signature = [hash base64EncodedStringWithOptions:0]; 
//Ds_Signature: kUVwanKNIlrvw3t56HUAYXSBmE/u6ruTj1r/FGOIiUg= 

Mes fonctions:

- (NSString *)hexadecimalString:(NSData*)data{ 
    const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; 
    if (!dataBuffer){ 
     return [NSString string]; 
    } 
    NSUInteger   dataLength = [data length]; 
    NSMutableString  *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)]; 
    for (int i = 0; i < dataLength; ++i){ 
     [hexString appendFormat:@"%02x", (unsigned int)dataBuffer[i]]; 
    } 
    return [NSString stringWithString:hexString]; 
} 


- (NSData*)encrypt3DES:(NSString*)data key:(NSString*)key{ 
    NSData *plainData = [data dataUsingEncoding:NSUTF8StringEncoding]; 
    const void *vplainText = (const void *)[plainData bytes]; 
    size_t plainTextBufferSize = [plainData length]; 
    size_t movedBytes = 0; 
    size_t bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1); 
    uint8_t * bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t)); 
    memset((void *)bufferPtr, 0x0, bufferPtrSize); 

    NSString *initVec = @"\0\0\0\0\0\0\0\0"; 
    const void *vkey = (const void *) [key UTF8String]; 
    const void *vinitVec = (const void *) [initVec UTF8String]; 

    CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt, 
             kCCAlgorithm3DES, 
             kCCOptionPKCS7Padding | kCCOptionECBMode, 
             vkey, 
             kCCKeySize3DES, 
             vinitVec, 
             vplainText, 
             plainTextBufferSize, 
             (void *)bufferPtr, 
             bufferPtrSize, 
             &movedBytes); 
    if (ccStatus == kCCSuccess) NSLog(@"SUCCESS"); 
    else if (ccStatus == kCCParamError) NSLog(@"PARAM ERROR"); 
    else if (ccStatus == kCCBufferTooSmall) NSLog(@"BUFFER TOO SMALL"); 
    else if (ccStatus == kCCMemoryFailure) NSLog(@"MEMORY FAILURE"); 
    else if (ccStatus == kCCAlignmentError) NSLog(@"ALIGNMENT"); 
    else if (ccStatus == kCCDecodeError) NSLog(@"DECODE ERROR"); 
    else if (ccStatus == kCCUnimplemented) NSLog(@"UNIMPLEMENTED"); 

    return [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes]; 
} 


-(NSData *)hmac256ForKeyAndData:(NSString *)data withKey:(NSData *)keyData{ 
    NSData *dataData=[data dataUsingEncoding:NSUTF8StringEncoding]; 
    NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; 
    CCHmac(kCCHmacAlgSHA256, keyData.bytes, keyData.length, dataData.bytes, dataData.length, hash.mutableBytes); 
    return hash; 
} 

PS: Les clés et les mots de passe sont faux, ne sont que pour les tests. ;)

Répondre

0

Il y a quelques erreurs:

Première: la version PHP utilise le mode CBC et la version iOS utilise le mode ECB. La valeur par défaut pour CCCrypt est le mode CBC, il suffit de supprimer kCCOptionECBMode. L'utilisation d'un null iv rendra le premier bloc non sécurisé, généralement un iv aléatoire est utilisé et préfixé aux données cryptées.

Deuxièmement: mcrypt ne prend pas en charge le remplissage PKCS # 7, il ne prend en charge que le remplissage de non-standard non standard. Par conséquent, il est nécessaire d'ajouter le remplissage aux données avant le cryptage.

De cette SO Answer:

Ajouter PKCS # 7 padding (php):
$block est la taille du bloc en octets et $str est que les données soient cryptées

$pad = $block - (strlen($str) % $block); 
$str .= str_repeat(chr($pad), $pad); 

Retirer PKCS # 7 remplissage (php):
$str est les données décryptées

$len = strlen($str); 
$pad = ord($str[$len-1]); 
$str = $strsubstr($str, 0, $len - $pad); 

Remarque: si les données sont exactement un multiple de la taille de bloc, un bloc entier de remplissage sera ajouté, ceci est nécessaire.

Voir PKCS#7 pour plus d'informations sur le rembourrage. Pour un débogage plus poussé, fournissez les vidages hexadécimaux de tous les paramètres et des données dans et hors du chiffrement: secretCode, Ds_Merchant_Order, iv et sortie chiffrée.

Enfin: Pour une meilleure sécurité, pensez à utiliser RNCryptor, disponible pour plusieurs plates-formes et langues. Il est bien vérifié, prend en charge les meilleures pratiques actuelles et est actuellement pris en charge.

+0

Le code PHP est une bibliothèque, je ne peux pas modifier cette bibliothèque. Je dois faire le résultat du cryptage dans iOS, est identique à crypter le bon résultat en PHP. – clasik

+0

Dans ce cas, vous devez supprimer le remplissage PHP null après le déchiffrement avec CCCrypt et supprimer l'option 'kCCOptionPKCS7Padding'. Tant que les données chiffrées par mcrypt n'ont pas le dernier octet de données de 0x00, supprimez simplement les caractères de fin 0x00. Comme mentionné précédemment, vous devez également supprimer l'option 'kCCOptionECBMode'. Il n'est malheureusement pas rare d'avoir un cryptage non sécurisé initialement utilisé et non corrigé. – zaph

+0

Remarque: CCCrypt ne signale pas un remplissage incorrect, ce qui n'est pas sûr. – zaph