AES-256-CBC encryption algorithm in react-native - react-native

Hi am trying to check the compatability of encryption done on BE.
BE provided the below code `
$secret_key = VALUE1`;
$secret_iv = VALUE2;
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', $secret_key);
$iv = substr(hash('sha256', $secret_iv), 0, 16);
openssl_encrypt($string, $encrypt_method, $key, 0, $iv)`
the openssl gave SNtvZ3Dpv1S88Ha6aVBdcg== when input string is abc
I tried few alogritham but I wasnt able to correctly match it with BE
he $key and $iv value I generated same as BE. but when it comes to encryption it doesnt give any result or saying Expected IV length is 16 but got 8
The following are the packages I tried
import Aes from 'react-native-aes-crypto';
Aes.encrypt(inputText, hash, _IV, 'aes-256-cbc').then(cipher => {
console.log('cipher', cipher); });
This throws an error Error: expected IV length of 16 but was 8
I checked the length of _IV and it is certanly 16
import CryptoAesCbc from 'react-native-crypto-aes-cbc';
CryptoAesCbc.encryptInBase64(
base64.encode(ivHash.substr(0, 16)),
base64.encode(hash),
'abc',
'128',
)
.then(encryptString => {
console.log('encryptString', encryptString);
})
.catch(error => {
console.log('error ', error);
});
This the encryptString value prints empty string
Please someone give me some insight into this.
FYI am checking in Android for the time being
EDIT 1
I red in some post about converting to _IV to hex
so I did this
Aes.encrypt(
inputText,
hash,
Buffer.from(_IV).toString('hex'),
'aes-256-cbc',
)
.then(cipherText => console.log('cipherText', cipherText))
.catch(error => console.log('error here', error));
It gave me wrong out out cipherText: yLvY847qCMHHGHdachjKGw==
Any help is appreciated
Thanks in advance

In the hash() function of the PHP code, the third parameter is false by default, so $key and $iv are returned as hex encoded strings and not as raw binary data.
For SHA256 with a digest output length of 32 bytes $key therefore has a length of 64 bytes, since $key is not explicitly truncated, unlike $iv.
Nevertheless, only the first 32 bytes of the 64 bytes are used for encryption, because OpenSSL/PHP silently truncates keys that are too large (and pads keys that are too short with 0x00 values) to achieve the specified length (32 bytes for AES-256-CBC).
On the CryptoJS side, both the hex encoding of key and IV must be taken into account as well as the truncation of the key.
A possible implementation with CryptoJS (referring to your solution in the chat) is:
var plaintext = "The quick brown fox";
var keyMaterial = "my key passphrase";
var ivMaterial = "my IV passphrase"
var truncHexKey = CryptoJS.SHA256(keyMaterial).toString().substr(0, 32); // hex encode and truncate
var truncHexIV = CryptoJS.SHA256(ivMaterial).toString().substr(0, 16); // hex encode and truncate
var key = CryptoJS.enc.Utf8.parse(truncHexKey);
var iv = CryptoJS.enc.Utf8.parse(truncHexIV);
var ciphertext = CryptoJS.AES.encrypt(plaintext, key, {iv: iv}); // default values: CBC, PKCS#7 padding
console.log('Ciphertext: ' + ciphertext.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
which gives the same ciphertext as the PHP code.
In general, it should also be noted that the use of upper and lower case letters is not consistently implemented in hex encoding. However, like PHP's hash() function, CryptoJS uses lowercase letters, so this is not a problem here.

Related

AES-CBC: using CryptoJS in React-Native and CryptoSwift in Swift

I'm building a React-Native app that uses NotificationServiceExtension on iOS to intercept encrypted notifications and decrypt them before showing to the user.
On the react-native side, I encrypt the message using CryptoJS:
const originalText = 'This will be encrypted';
const theAESKeyWordArray = CryptoJS.enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
const iv = CryptoJS.enc.Hex.parse("101112131415161718191a1b1c1d1e1f"); // Test iv text is in hexadecimal and converting it to wordArray
const ciphertext = CryptoJS.AES.encrypt(originalText, theAESKeyWordArray, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: iv
}).toString();
On the NotificationServiceExtension side (Swift) using CryptoSwift, after receiving the notification, I'm trying to decode it using the following code:
The "encryptedBody" variable when printed out to console looks exactly the same as console.log(ciphertext) in react-native side. I can also see that when printed out the clearAESKey.string(encoding: .utf8) is the same as that which I used to to encrypt it on the react-native side.
let AESKey = Array<UInt8>(hex: try clearAESKey.string(encoding: .utf8))
let iv = Array<UInt8>(hex: "101112131415161718191a1b1c1d1e1f")
let bufContent: [UInt8] = [UInt8] (encryptedBody.utf8)
let aes = try AES(key: AESKey, blockMode: CBC(iv: iv), padding: .pkcs7)
let padded = Padding.pkcs7.add(to: bufContent, blockSize: AES.blockSize)
let decryptedBody = try aes.decrypt(padded)
let decryptedData = Data(decryptedBody)
let decryptedString = String(decoding: decryptedBody, as: UTF8.self)
print(decryptedString)
The printed output of decryptedString is something like this "L����JtϑJ��E7sD��)�ga�J׊p�"
Any ideas what I am doing wrong?
Thanks anyone for your help.
Key and IV must be hex decoded, the ciphertext returned by the CryptoJS code must be Base64 decoded. Before decryption, no padding must be applied:
let AESKey = [UInt8](hex: "000102030405060708090a0b0c0d0e0f")
let iv = [UInt8](hex: "101112131415161718191a1b1c1d1e1f")
let bufContent = [UInt8](base64: "GErWj4t2vW0u1o1Z9iUNo8gxkO1O0Bl8l3amQ86EKKw=")
let aes = try AES(key: AESKey, blockMode: CBC(iv: iv), padding: .pkcs7)
let decryptedBody = try aes.decrypt(bufContent)
let decryptedString = String(bytes: decryptedBody, encoding: .utf8)!
print(decryptedString) // This will be encrypted
Keep in mind that a static IV is insecure (for testing purposes this is of course OK).

SalesForce marketing System not getting decrypted in Using java Crypto

I need some help in understanding, how to decrypt SalesforceMarketingCloud encrypted String into java.
I should admit that I have few things missing in my questions but this is what ever I have been provided so far
Algorithm – AES256, 256 Bit
Initilization vector – 16 bytes
Salt – 8 Bytes
Passphrase – “presharedpassphrase123”
As per my understanding the Input String has been encrypted using
EncryptSymmetric(#Clear, "AES", #null, #Passphrase, #null, #Salt, #null, #IV)
But when I try to decrypt it at Java side, it fails for various reason.
My best shot has been getting a garbage String as output so far when I used combination like below
NoPadding, CBS, and hashing my passphrase(which is 22 char long) to 32 bit using SHA-256
Can anyone please help, any Java code sample which you successfully used in past.
private String decryptWithKey(String myKey, byte[] strToDecrypt) throws Exception
{
MessageDigest sha = null;
try {
key = myKey.getBytes(CHAR_SCHEME);
sha = MessageDigest.getInstance("SHA-256");
key = sha.digest(key);
key = Arrays.copyOf(key, 32);
secretKey = new SecretKeySpec(key, ALGO);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
byte[] ivByte = new byte[cipher.getBlockSize()];
ivByte = hexStringToByteArray("0716A494177F29F102AF33AFD0253BA1");;
System.out.println(new String(ivByte));
// IvParameterSpec ivParamsSpec = new IvParameterSpec(IV);
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParamsSpec);
setDecryptedString(new String(cipher.doFinal(strToDecrypt)));
}
catch (Exception e)
{
System.out.println("Error while decrypting: "+e.toString());
throw e;
}
return decryptedString;
}

Creating a private/public key with 64 characters that are already known using bitcoinjs

So I'm trying to create a private/public key from 64 characters that I already know using bitcoinjs with the code below:
key = Bitcoin.ECKey.makeRandom();
// Print your private key (in WIF format)
document.write(key.toWIF());
// => Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct
// Print your public key (toString defaults to a Bitcoin address)
document.write(key.pub.getAddress().toString());
// => 14bZ7YWde4KdRb5YN7GYkToz3EHVCvRxkF
If I try to set "key" to my 64 characters instead of "Bitcoin.ECKey.makeRandom();" it fails. Is there a method or library that I overlooked that would allow me to use the known 64 characters in order to generate the private key in wif format and the public address?
Thanks in advance to anyone that may be able to offer some help.
You should use fromWIF method to pass your own data.
from source code of eckey.js
// Static constructors
ECKey.fromWIF = function(string) {
var payload = base58check.decode(string)
var compressed = false
// Ignore the version byte
payload = payload.slice(1)
if (payload.length === 33) {
assert.strictEqual(payload[32], 0x01, 'Invalid compression flag')
// Truncate the compression flag
payload = payload.slice(0, -1)
compressed = true
}
To create WIF from your key please follow https://en.bitcoin.it/wiki/Wallet_import_format
Here is interactive tool http://gobittest.appspot.com/PrivateKey
The solution to generate private and public key:
//public-key
var address = eckey.getBitcoinAddress().toString();
var privateKeyBytesCompressed = privateKeyBytes.slice(0);
privateKeyBytesCompressed.push(0x01);
var privateKeyWIFCompressed = new Bitcoin.Address(privateKeyBytesCompressed);
privateKeyWIFCompressed.version = 0x80;
//private-key
privateKeyWIFCompressed = privateKeyWIFCompressed.toString();
Take a look at moneyart.info for beautifully designed paperwallets.

How to get correct SHA1 hash of BLOB using CryptoJS?

CryptoJS v3.1.2, sha1.js rollup
In JS I want to calculate the SHA1 of a blob before sending it to the server. On the server I want to calculate the SHA1 of the resulting file and compare it to the SHA1 received from JS. The problem is that the hash generated by CryptoJS.SHA1() is incorrect (always 9844f81e1408f6ecb932137d33bed7cfdcf518a3)
JS Code:
function uploadFileslice (slice) { // slice is a blob
var fileReader = new FileReader()
fileReader.onload = function(event){
var arrayBuffer = event.target.result
var wordArray = CryptoJS.lib.WordArray.create(arrayBuffer)
var sha1crc = CryptoJS.SHA1(wordArray).toString(CryptoJS.enc.Hex)
//etc
requestParams.append('fileslice', slice)
requestParams.append('sha1crc', sha1crc)
//etc
}
fileReader.readAsArrayBuffer(slice)
}
PHP code:
$file_crc = sha1_file($_FILES['fileslice']['tmp_name']);
if ($_REQUEST['sha1crc'] !== $file_crc) {
echo "Invalid CRC: {$_REQUEST['sha1crc']} (expected $file_crc)";
return;
}
Output:
Invalid CRC: 9844f81e1408f6ecb932137d33bed7cfdcf518a3 (expected 3ebe2cd2d8fd8d8f977b6d715f0b1adf5b08b407
I was hoping for something like myHash = CryptoJS.SHA1(blob)
From the info that you've provided I'm not sure exactly how you have things setup but in order for ArrayBuffers to be supported you have to include components/lib-typedarrays-min.js.
There's a discussion about this at https://code.google.com/p/crypto-js/issues/detail?id=67.
Hope this helps!
If you are using modules and import you can:
import Hex from 'crypto-js/enc-hex'
import WordArray from 'crypto-js/lib-typedarrays'
import sha1 from 'crypto-js/sha1'
const hash = sha1(WordArray.create(arrayBuffer)).toString(Hex)

the signature includes en embedded timeStamp but it could not be verified

I've just added timestamp to my pdf. signature is valid. timestamp token is correct too (I checked already). but adobe reader tells me that "signature includes an embedded timestamp but it could not be veridied".
AttributeTable unsigned = signerInformation.getUnsignedAttributes();
Hashtable<ASN1ObjectIdentifier, Attribute> unsignedAttrHash = null;
if (unsigned == null) {
unsignedAttrHash = new Hashtable<ASN1ObjectIdentifier, Attribute>();
} else {
unsignedAttrHash = signerInformation.getUnsignedAttributes().toHashtable();
}
unsignedAttrHash.put(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken, signatureTimeStamp);
SignerInformation newSignertInformation = SignerInformation.replaceUnsignedAttributes(si, new AttributeTable(unsignedAttrHash));
I fount this code at stackowerflow. it works. it's really correct code. finally I have new SignerInformationStore and new CMS Signed Data like this
CMSSignedData.replaceSigners(oldCMSSignedData, newSignerStore);
but maybe something is missing in my PDF? certificate or something like that?
that's sample pdf
The message imprint in the signature-time-stamp seems to be not correct. It is expected to have the SHA256 of the signature value in this message imprint.
SHA256 of the signature value:
1b4532052d612ca32ae96b9a8e7aa6d64ae6c69dc00e1b7b31394ac3b54c4049
The message imprint in the time-stamp token:
E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855