title: 3DES encrypt result in PHP, JAVA and .NET produces different result from 3DES iOS
body: <p>I'm trying to upgrade my current app in iOS 8, to adapt to the new encryption SHA256 of Redsys / Sermpa.</p>
  
  <p>But I have problems in data encryption. In PHP, Java and .NET I get a result, completely different from iOS.</p>
  
  <p>I think the problem must be in the 3DES IOS CCCrypt.</p>
  
  <p>The PHP, JAVA and .NET code is a library, I can not alter that library.</p>
  
  <p>I have to make the result of encryption in iOS, is identical to right result encrypt in PHP, JAVA and .NET.</p>
  
  <p><strong>Library Java Code:</strong></p>
  
  <pre><code>    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 &lt; numeroCerosNecesarios; i++) {
                  array.write(0);
              }
              byte [] cleartext = array.toByteArray();
  
              ciphertext = desCipher.doFinal(cleartext);
          } catch (Exception e) {
              e.printStackTrace(System.err);
          }
          return ciphertext;
      }
  </code></pre>
  
  <p><strong>Library PHP Code:</strong></p>
  
  <pre><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 &gt;= 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-&gt;encodeBase64($hash);
      //Ds_Signature: hueCwD/cbvrCi+9IDY86WteMpXulIl0IDNXNlYgcZHM=
  </code></pre>
  
  <p><strong>Library .NET Code:</strong></p>
  
  <pre><code>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);
              }
          }
  </code></pre>
  
  <p>**********************------------**********************------------**********************</p>
  
  <p><strong>My Objective-C Code:</strong></p>
  
  <pre><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=
  </code></pre>
  
  <p><strong>My Functions:</strong></p>
  
  <pre><code>- (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 &lt; 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) &amp; ~(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,
                                         &amp;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;
  }
  </code></pre>
  
  <p>P.S.: Keys and passwords are fake, are just for testing. ;)</p>