2015-11-19 3 views
-1

Я пытаюсь обновить свое текущее приложение в iOS 8, чтобы адаптироваться к новому шифрованию SHA256 Redsys/Sermpa.Результат шифрования 3DES в PHP, JAVA и .NET дает отличный результат от 3DES iOS

Но у меня проблемы с шифрованием данных. В PHP, Java и .NET я получаю результат, полностью отличный от iOS.

Я думаю, что проблема должна быть в 3DES IOS CCCrypt.

PHP, JAVA и .NET-код - это библиотека, я не могу изменить эту библиотеку.

Я должен сделать результат шифрования в iOS, идентичен правильному результату шифрования в PHP, JAVA и .NET.

Библиотека 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; 
    } 

библиотека PHP код:

$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= 

Библиотека .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); 
      } 
     } 

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

My Objective-C Code :

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= 

Мои функции:

- (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: Ключи и пароли являются поддельными, только для тестирования. ;)

ответ

0

Есть несколько ошибок:

Первое: PHP версия использует режим CBC и версия IOS использует ECB режим. Значение по умолчанию для CCCrypt - режим CBC, просто удалите kCCOptionECBMode. Использование null iv сделает первый блок незащищенным, обычно используется случайный iv и добавляется к зашифрованным данным.

Во-вторых: mcrypt не поддерживает заполнение PKCS # 7, оно поддерживает только нестандартное небезопасное заполнение нулей. Поэтому перед шифрованием необходимо добавить дополнение к данным.

Из этого SO Answer:

Добавить PKCS # 7 отступы (PHP):
где $block размер блока в байтах и ​​$str это данные, которые должны быть зашифрованы

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

Удалить PKCS # 7 заполнение (php):
, где $str - дешифрованные данные

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

Примечание: если данные точно кратно размеру блока, будет добавлен весь блок дополнений, это необходимо.

См. PKCS#7 для получения дополнительной информации о заполнении.

Для дальнейшей отладки предусмотрены шестнадцатеричные дампы всех параметров и данных в шифровании и из него: secretCode, Ds_Merchant_Order, iv и зашифрованный вывод.

И наконец: для обеспечения лучшей безопасности рассмотрите возможность использования RNCryptor, который доступен для нескольких платформ и языков. Он хорошо проверен, поддерживает текущую передовую практику и в настоящее время поддерживается.

+0

PHP-код - это библиотека, я не могу изменить эту библиотеку. Я должен сделать результат шифрования в iOS, идентичен правильному результату шифрования в PHP. – clasik

+0

В этом случае вам нужно удалить заполнение пула PHP после дешифрования с помощью CCCrypt и удалить опцию 'kCCOptionPKCS7Padding'. Пока данные, зашифрованные mcrypt, не имеют последнего байта данных 0x00, просто удалите конечные 0x00 символов. Как уже упоминалось, вам также необходимо удалить опцию 'kCCOptionECBMode'. К сожалению, нередко возникает небезопасное шифрование, которое первоначально использовалось и не исправлялось. – zaph

+0

Примечание: CCCrypt не сообщает о некорректном заполнении, делая это небезопасно. – zaph

Смежные вопросы