Tengo que realizar un cifrado en específico para conectarme con mi pasarela de pago.
Estoy usando la librería crypto-js ya que pensé que al ser Javascript funcionaría bien con Velneo.
Este es el código que me han enviado de ejemplo desde la pasarela de pago (he cambiado los datos por seguridad).
<html>
<head>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/tripledes.min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/hmac-sha256.min.js'></script>
<script>
function convertArrayToASCII(ivArray) {
let IV = '';
for (let i = 0; i < ivArray.length; i++) {
IV += String.fromCharCode(ivArray[i]);
}
console.log(IV);
return IV;
}
function des_encrypt(message, key) {
let ivArray = [0,0,0,0,0,0,0,0];
let encode_str = CryptoJS.TripleDES.encrypt(message , key, {
iv: CryptoJS.enc.Utf8.parse(convertArrayToASCII(ivArray)),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return encode_str.toString();
}
function stringBase64Encode(input) {
let utf8Input = CryptoJS.enc.Utf8.parse(input);
return CryptoJS.enc.Base64.stringify(utf8Input);
}
function bytesBase64Encode(input) {
return CryptoJS.enc.Base64.stringify(input);
}
function base64Decode(input) {
//Decodifica el Base64 y devuelve el array de bytes directamente
return CryptoJS.enc.Base64.parse(input);
}
function calcularFirma() {
let merchantOrder = '123456789';
console.log(merchantOrder);
let data = {
'DS_MERCHANT_AMOUNT': '1',
'DS_MERCHANT_CURRENCY': '978',
'DS_MERCHANT_MERCHANTCODE': '353264575',
'DS_MERCHANT_MERCHANTURL': 'http://192.168.1.139/prueba_tpv/URLNOTI.pro',
'DS_MERCHANT_ORDER': merchantOrder,
'DS_MERCHANT_TERMINAL': '100',
'DS_MERCHANT_TRANSACTIONTYPE': '0'
}
console.log(data);
let encodedParameters = stringBase64Encode(JSON.stringify(data));
console.log('base64', encodedParameters)
//No hay que pasar la firma a base64 puesto que ya está en base64
//Lo que hay que hacer es decodificarla de bas64 y tal cual pasarla como clave para encriptar el Nº de pedido
//La encriptación tiene que ser con ZeroPadding
let encodedSignature = 'SGVsbG8sIFdvcmxkIQ=='; //Valor de la clave en el portal de administración
let encodedSignatureDES = des_encrypt(merchantOrder, base64Decode(encodedSignature)); //Se cifra el número de pedido con la clave para obtener la clave de operación
console.log('base64Decode(encodedSignature):', base64Decode(encodedSignature))
console.log('Clave de la operación:', encodedSignatureDES);
let encodedDsSignature = CryptoJS.HmacSHA256(encodedParameters, base64Decode(encodedSignatureDES)); //Se calcula el HMAC de los parámetros en Base64 con la clave de operación
console.log('base64Decode(encodedSignatureDES):', base64Decode(encodedSignatureDES))
console.log('HMAC', encodedDsSignature);
let dsSignature = CryptoJS.enc.Base64.stringify(encodedDsSignature); //Se pasa a Base 64
console.log('HMAC base64', dsSignature)
let encodedRequest = { 'Ds_MerchantParameters': encodedParameters, 'Ds_Signature': dsSignature, 'Ds_SignatureVersion': 'HMAC_SHA256_V1' }
console.log(encodedRequest)
//Esto es para validarlo contra test por redirección. A ellos no les sirve
document.pago.datos.value=JSON.stringify(data);
document.pago.Ds_MerchantParameters.value=encodedParameters;
document.pago.Ds_Signature.value=dsSignature;
}
</script>
</head>
<body>
<a href='javascript:calcularFirma()'>Calcular Firma</a>
<form name='pago' action='https://sis-t.redsys.es:25443/sis/realizarPago' method='POST'>
Datos en claro:
<textarea name='datos' cols='80' rows='5'>
</textarea></br>
Datos en Base64:
<textarea name='Ds_MerchantParameters' cols='8' rows='5'>
</textarea></br>
Firma calculada:
<input type='text' name='Ds_Signature' value='' size='100'/></br>
Versión Firma:
<input type='text' name='Ds_SignatureVersion' value='HMAC_SHA256_V1'/></br>
<input type='submit' value='Probar contra tes'/>
</form>
</body>
</html>
Y este es mi código de Velneo
#include "(CurrentProject)/crypto-js-4.1.1/crypto-js.js"
#include "(CurrentProject)/crypto-js-4.1.1/tripledes.js"
#include "(CurrentProject)/crypto-js-4.1.1/hmac-sha256.js"
// -----------------------------------------
// Variables Velneo a variables JavaScript
// -----------------------------------------
var clave = theRoot.varToString("CLAVE");
var num_ped = theRoot.varToString("NUM_PED");
var ds_mp = theRoot.varToString("DS_MP");
// -----------------------------------------
function stringBase64Encode(input) {
var utf8Input = CryptoJS.enc.Utf8.parse(input);
return CryptoJS.enc.Base64.stringify(utf8Input);
}
// -----------------------------------------
function convertArrayToASCII(ivArray) {
var IV = "";
for (var i = 0; i < ivArray.length; i++) {
IV += String.fromCharCode(ivArray[i]);
}
alert("IV:" + IV);
return IV;
}
// -----------------------------------------
function encryptByDES(message, key) {
var ivArray = [0, 0, 0, 0, 0, 0, 0, 0];
var encrypted_tresdes= CryptoJS.TripleDES.encrypt(message, key, {
iv: CryptoJS.enc.Utf8.parse(convertArrayToASCII(ivArray)),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return encrypted_tresdes.toString();
}
// -----------------------------------------
function base64Decode(input) {
//Decodifica el Base64 y devuelve el array de bytes directamente
return CryptoJS.enc.Base64.parse(input);
}
// -----------------------------------------
var encodedParameters = stringBase64Encode(ds_mp);
//Se cifra el número de pedido con la clave para obtener la clave de operación
var clave64 = base64Decode(clave);
var signatureDES = encryptByDES(num_ped, base64Decode(clave));
//Se calcula el HMAC de los parámetros en Base64 con la clave de operación
var signatureDES64 = base64Decode(signatureDES);
var signatureHMAC = CryptoJS.HmacSHA256(encodedParameters, signatureDES64);
//Se pasa a Base64
var dsSignature = CryptoJS.enc.Base64.stringify(signatureHMAC);
theRoot.setVar("DS_MP_64", encodedParameters);
theRoot.setVar("DS_SIGNATURE", dsSignature);
Lo que he hecho para poder importarlo ha sido copiar el código de la propia url y pegarlo en un archivo en Velneo
https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
Pero esta versión del código .min, por alguna razón no compila y tampoco sé como resolver el error

Lo he intentado entonces con el código que hay aquí
https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.js
También da error de compilación
Pero quitando el urlsafe = true y dejando solo urlsafe, me deja compilar.
Sin embargo, a la hora de ejecutar el código veo resultados dierentes entre el que me han enviado de ejemplo y el que estoy intentando ejecutar en velneo
Mientras que esta función de codificar a Base64 funciona bien y me devuelve el resultado esperado
Esta otra de decodificar de base64 no devuelve el mismo resultado que en el ejemplo que me han pasado
Resultado del html de ejemplo
Resultado en Velno
Este dato erróneo me condiciona el valor del resto de los datos cifrados y por tanto la pasarela de pago me devuelve error.
He conseguido conectarme a la pasarela de pago de esta forma
Pero ni me gusta la idea de que haya datos accesibles desde el html, ni me sirve después para desencriptar los datos de respuesta, ya que me los envía a la url que estoy indicando en el JSON.
¿Podría afectar que no sea la versión . min del archivo? ¿Porque no compila en Velneo este código de Javascript?
¿Es posible que haya otra forma de hacer esta encriptación?
¿Alguien que haya hecho algo parecido?
Gracias por leer hasta el final
Espero que puedan ayudarme