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. ;)
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
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
Remarque: CCCrypt ne signale pas un remplissage incorrect, ce qui n'est pas sûr. – zaph