I'm currently encrypting data in PHP as follows:
//$sMessage is the input to encrypt.
//$sPublicKey is the public key in PEM format.
openssl_public_encrypt($sMessage, $sEncrypted, $PublicKey, OPENSSL_PKCS1_OAEP_PADDING);
//$sEncrypted will now store the resulting text.
Here's an example of the code used to generate the key in PHP:
$aConfig = array(
"digest_alg" => "sha256",
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$res = openssl_pkey_new($aConfig);
//$sPassPhrase is the pass phrase.
openssl_pkey_export($res, $sPrivateKey, $sPassPhrase);
//$sPrivateKey is the key (in PEM format).
And my decryption is using a private key that's protected by a pass phrase.
//$sPrivateKeyWithPassPhrase is the protected private key in PEM format.
//$sPassPhrase is the pass phrase to protect the key.
$newRes = openssl_pkey_get_private($sPrivateKeyWithPassPhrase, $sPassPhrase);
//$sEncrypted is the encrypted text (ciphertext).
openssl_private_decrypt($sEncrypted, $sDecrypted, $newRes, OPENSSL_PKCS1_OAEP_PADDING);
//$sDecrypted is the decrypted text (plaintext)
I've also found out how to decrypt with Python using the cryptography library (which you can learn about here):
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
#passphrase is the pass phrase
passphrase_bytes = bytes(passphrase, 'utf-8')
#privatekey is the encrypted private key
private_key = serialization.load_pem_private_key(
privatekey,
password=passphrase_bytes,
)
#ciphertext is the text to be decrypted
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
#plaintext will be the decrypted result.
However, I've been struggling to find a comparable function in JavaScript.
The best answer I found so far was this one: RSA Encryption Javascript
However, it doesn't seem like keys are in PEM format and when I go to the pidCrypt homepage to get more documentation, it's a 404 error.
I found this one as well: PHP's openssl_sign Equivalent in Node JS
The NodeJS library in general seems to have the right functions but when I went through the NodeJS documentation the Quick Start Guide seems to suggest that in order to use NodeJS I have to first install software and set up a web server. According to how to run node.js client on browser, it's not possible "Node.js is not browser javascript. There are many parts of it that use OS features not available in a browser context." (I'm hoping for something I can run in a native browser on the client-side.)
Someone suggested in a comment that I could use WebCrypto. After some struggle to figure out where to download it, I found it's actually native to the browsers (which was a pleasant surprise). However, I haven't been able to figure out how to import a PEM key from the documentation, and when I went to generate a key then export it, the only available formats were "jwk" (some sort of JavaScript object), "spki" (some kind of array buffer), and "pkcs8" (which I only got DOMException: key is not extractable). Nothing looks remotely like the OpenSSL PEM format. (I believe this is PKCS1.)
When I did "crypto.subtle.importKey" it wanted 5 different parameters (format, keyData, algorithm, extractable, keyUsages). None of those accept the PEM string. After a bit of struggle I did find SubtleCrypto importKey from PEM which confirmed that it's possible if you do fancy manipulation to import a PEM public key, however that's for public keys in PEM format and I have no idea how to handle pass phrases (and really I'd rather not program that all by hand). Then I found How can I import an RSA private key in PEM format for use with WebCrypto? and Javascript, crypto.subtle : how to import RSA private key? however those basically told me it's not possible unless I go and convert the private key to PKCS8 using a command line OpenSSL (that also has to be installed separately and I remember was a huge pain to get on Windows). And once I get past that hurdle, I'm still not sure how I would go about getting an equivalent pass phrase protection in PKCS8. I'm hoping there's something similar that ideally supports PKCS1 to do the same as the PHP and Python code above, and I can run it 100% in the native browser. (Importing more JavaScript code is okay.)
I'd ideally like to find a simple working JavaScript example for OpenSSL RSA decryption, equivalent to the PHP or Python ones above. If I have the private key PEM string, the pass phrase, and the cipher text it can give back the plaintext.
Thank you very much! I appreciate all your help a ton and you can save me many hours!
PKCS#1 Versus PKCS#8
Note that while private keys generated without pass phrases in PHP are PKCS#1, the private key generated from PHP with a pass phrase is actually PKCS#8 (see this link for how to determine which standard applies to a private key).
Third Party Library Required
In order to work with PEM-format keys, a custom JavaScript library (or other custom code) is required. There are various libraries at this link which you can look at. Many are not maintained anymore.
This example uses the Forge JavaScript library, but you could also use a different library.
Installing/Importing Forge
While there are various ways to build the Forge environment, the easiest is to add the following HTML code prior to where you need to do encryption/decryption:
<script src="https://cdn.jsdelivr.net/npm/node-forge#0.7.0/dist/forge.min.js"></script>
Performing RSA Decryption
The following JavaScript code will perform decryption using the Forge library with a private key that's passphrase-protected:
// Import an PKCS#8 encrypted key from PHP
//sEncPkcs8Pem = The encrypted PEM key in a string.
//sPassPhrase = A pass phrase string to use for decryption.
//bCipherText = The encrypted cipher text (string of bytes).
var encryptedPrivateKeyInfo = forge.pki.encryptedPrivateKeyFromPem(sEncPkcs8Pem);
var privateKeyInfo = forge.pki.decryptPrivateKeyInfo(encryptedPrivateKeyInfo, sPassPhrase);
var pkcs8Pem = forge.pki.privateKeyInfoToPem(privateKeyInfo);
var privateKey = forge.pki.privateKeyFromPem(pkcs8Pem);
var sDecrypted = privateKey.decrypt(bCipherText, 'RSA-OAEP');
//sDecrypted will store the result.
Full Working Example
The following is a full working example with a 4096-bit key. The JavaScript imports an encrypted private key (PKCS#8 format, PEM encoded) and successfully decrypts a ciphertext.
The encrypted key and ciphertext were both generated using the posted PHP code.
The JavaScript library applied is forge.
<script src="https://cdn.jsdelivr.net/npm/node-forge#0.7.0/dist/forge.min.js"></script>
<p style="font-family:'Courier New', monospace;" id="pt"></p>
<script>
var encPkcs8Pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJnDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIxjk2j/jhKPECAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECMWHokN4f1pIBIIJSGsi3CbrV4Uf
QL70dh+nKI0+PbSKlpx4CJZVARiTonO26+YathAgo/F6TKY+MZAfctuAg38EDo6u
zyjPxkrz8Ha1rIhBioFg4Tyem4s/16F4dVw9D4+dy/ORCk7PvbCg++lCCt3lVAqF
Q+zX8X9ygXza+PyHlJzAi6o2MQsoxC37cBvhLmPGSbVFPBAhSmfsWqct7StMp872
jIk/2x1xt0gZlSIayefLUEc/OP1sBXoBeFEFF3nxZrpMaCixElEyMKWHaQPDberm
gkbuvwCmwC/rFCO4BG4GLcgWzQ8msYBIE0wS+QoLzBqE+RrAXPgTpFto2/S/SZ2U
2zRiyXtDG6AK0yBBj9IJcSUHbNO7JvBsbxg9LO8Y+HxkwPQkQSF4CABsuFXeZ75a
eXs2AaptSmj5rjHHRoYKPB1Gsi7IkLa0q9otDCA2veDZRyh1OAhasZ382F3KQvGa
z8JQ0sahKLDUWdb9R0KVnEVurCnz4gutthMwXyfBJrAO9W9q0f3R40OOQvWxhTzX
cre04g8ihlYE39JdCWL09yctBXaDbGDMd3qIyo6+fHllVpRJVBzQB7mu2SAd1ZAQ
LcIpq4a83/82IGWN7oOkwmtceqpZNKo53SPEzHmU8sz+ZZSEDk5blDPrZLpypStU
MeS4vvRfartTtfgzD+nr5ulAUCPHs3EgentQAg92kHHs1znFW0oc5Iuyr57RAFvh
qbAgeUFKPIq/8lcAJkrPLmPeS/HkA6oNr2HC/+IgdUNBVUPOdp8tg8R+S6c3jt1x
fH9WWHT+xARK8Eo/5sQwdlb74ix+PkKEuf1EziYDZ/QFrsV72Fy2UZahKO2OmVHr
ZF3GN08gCL7Oh5Uo3fip5sVctxz1sD1RpAR4ClvVAJc+NbReKw7Oi9LKqQ0+8n6l
YwXTcRmkYv5ZU1mQedCQLv/CaelcDZ6o+7cTiNtpMP1kI05pux8nZISq9U3sL6HR
b2cWEiVtUf/aLg5kBp3RiWDCsXazZ2JPovgp4IvhHzRJvRauwlfKmCNYh5aeoAAF
NYtPhT1CY9WW1tsRvsr8KmaG4kB1wMHVaidGz3l2yVJmy+FVlylU1Uy+bZ5Km+77
ynREheQ3cwvG+n0IDJDTbmchnEB+B1eGuaoepjlVPLR291gRESTwMwUO2Rjc3Vu4
SD0FByqNeOQBfjTQJdXoKeWiSuvo9syC/1N6bsT88y/rOIqB8UDSBnrxSAvu3WGW
2MfJhuG8dQe056T5zkftifInFpwph+hHi589+LmuTq93iplKxQsJWEESe77OdSTl
Bg9MCOeBMa+sR3FDVDjGZ2UlscCp51SRXkbVPDkwnrPayqG6PNsFO8Hb1CHmzISi
K8ZnTrvgrIvLQ2QrpJZp5YvLG6V0rpBoII2cEwxDqoKcvAt46iIcTIj9UFs3iEPx
QLvtGvgm0xQXxVkrv3VDykUwMM+STySWJkJpT/1559XQytigRct+Ha5MpRzAHyo8
d6mV0Zi6Zh5GTQ/rO3+vbNXQQPy79f9Zrpne10GG+YltOHNbCDHz4sTBbvsAJvdz
nuMMG9Nt8sQ14XkH88VQVOk603MIHuoc7wp//6Z64sTd9ktu/Sm08vBtU/f7cslc
bjnP/ZH1JTaAILHyEfgdnVBacf2y/SrlEp2X0Ql/fu49UmIoT7ykcwJnhQNaXZ3N
M5lSqpNlB+lfshNbLHMaAp6sv8WARkK6etartmKveoZaJVhMicfvIrwlcMirO3Li
h5j97ZE8jxNyeGUV4425XIH4uN5qnlqxBVkCT5lln8GcPK/9Vkm/lUn/nXdGkFV4
4LOpmM7637N3KVah1iBL5LjEh5qXXgmVUdeiEQwXlLwIq33WszJLSSmI/wDC6H6N
uyG5u3Fx2gBZ9XCuJffoKJhH9UtIghIbilgNORc+8IE3w4beqFAHU9lbJeV85DMb
f3PbgLwN5Wc8hr6wPsK1ygJZhf+zzMQ67apa/pa2OuIRIYmmiee2VGxEJDCKUmFW
mIxqnZBsmDG1ajCFnIZ3EAwNhaYvVDrdoj5tYnwaflW1+WTAN7NqFGvmEZakJ2A+
tbRdbFIfxBrrbI3MNYMCx2w1hQHOCogLUsrc8vOM79Uv2z9LiPPmZocKnWv4NFR8
9rHPdFIhBOdsE6bfAG+UjpUcFJMblYwevVmu/te6p/TXEkosxcPuWJH8nXZ4uyx2
LO0FnvFMjQgAP3GShqjjrnDLgabC6Fx+I0kTJNdUYvFHUfyOK1Nszi1QODz7CP6Z
NglJoeFWCvtfmMGxM55qQJUFq1iacwAekW+K913WlPNCssXS3lWyenPOzgj40klS
e5RirohgDyhYONhPQVEsWRQsKcLIDC2q3l0jTbkfshWtaxwh3NGCdDTRoB/Aedy1
egq/HLJrQgGozQ+o130MIVLWhMuoOLIIl1XEFPtoT6ZLpwCh+HTL/tSdw7+QajV5
uZ+XxLc6lkcrJg4RvQjRm2aHsqi3HbBX+ydn2nAkuv6jPnw9EsAaAV4OWqYI7/R6
Zk6lncr6PmXABooFVpKg2WeTTp0j6Ye4M1QgxXosdtQjmuNRaNo2/QW2p3P0Sgvp
FsSwmWU1mTw9zPItQs9Y+ij/r27v5Atxy9D6RHU7QysjcMceMgUf9zeu3S1IOt2I
Rz2NYEhKqcVhne4yXMFO6dhdBZa3fyO0mWU1LyELykwjsZ/9KdFDlvksI9vFJ7zI
PWIUpW7EOKdLTHunXZu6Dn59fQqJYLFVlf4FgJTT4/YshIS0Nu+MeS45HQY7G3Up
QHXJ2TjHXVHV4amajkCLhSgaP7C59i8L9f+spWCu5v/8KKx6XLLbO6izI8TpWPW/
7rAysCmd9uNTTzJtUQJoBVZ1r8p7xoQXtkegqyE5/zsldIzSeC8/yr+XaZ2CK7zo
NIdwzqjFtpkcvsCQT3xLmGvLWJM9Jai1Hpfuhaggl9z7lo/i2rTsSIJRPa1BrSnm
+ntlsNo3r+RSoI+Tmi1MKzz2p+X4rXlD0tfPGm/yzuBXx8mtbZVX5yBNEI2l+EwN
EqPR5qHuobYfK8aZ7juB+AHoVlrGM26Q1PghHOFPc1dZVm3K+fThl19t/jdVve6Q
6NKAggLjuyEU4f+MELA8fwq7/66wqfgWIcBdGpn0npI23nx24jlfiKmmacBrKAHM
ij9mm4GhutigIoP4Wx/NUA==
-----END ENCRYPTED PRIVATE KEY-----`; // 4096 bit key!
// Import an PKCS#8 encrypted key from PHP
var encryptedPrivateKeyInfo = forge.pki.encryptedPrivateKeyFromPem(encPkcs8Pem);
var privateKeyInfo = forge.pki.decryptPrivateKeyInfo(encryptedPrivateKeyInfo, prompt("Enter pass phrase", "testkey"));
var pkcs8Pem = forge.pki.privateKeyInfoToPem(privateKeyInfo);
var privateKey = forge.pki.privateKeyFromPem(pkcs8Pem);
// Decrypt ciphertext from PHP
var ciphertext = forge.util.decode64("lHIspL7aAlnbUdQn6VVY2AS3Ybs/H0fK7N4owfPe6OtzMmX88XOI+2FyEnNyCal6krnfdHYa2JWeWAsyLf484sT2BmvNPxWyYsrnpulKog0lhkeUFppGdhdOHCf7KU47L5p6uYtZmv926ACfhwqMo4M66n/Gkliocol+esavVcfZcjuAw+ELnYkx/TufinR772jBLxVWueGyGcEokI9osDCDpXptmJqpiNRzIrf2kHdk2F/bXRPyE+vrQKFzbyMSpBj3xKtsYDiJ5xDq0qtYY+GCRJNMucPFqOTiFN18EE3z8y/tq5n9Ae/VS8wMxn51rB5JBRmYg3vlM4JLolqNnP3t8OD+DqAeavYjAnairLV0esxzjdkUDpfmFrsYBZWfe5rMzO55drDdsQpGI9LGeX5/TUQpqJWBNZ7QXnbxEiQ2ATXH+ToaeZe3mMkPKuogKM2aEViLzdYB0plbQnoWPAG4OH9pYPGj1KYwdQG5UoF0Ew6Y93uSG3uJ6mcdZZ9gJA0+hpVHOchuAvtZ+vuIV4tzWGfvvnAND54U5sS95EGRj8w/ukgswgOfg/k9iKN3Xlh5N23BYyoLajZVN92cVw6I3XpNOWjlHcO04EhLXaxIeaEMsYYqq3GDBtxpbXfARVjokMeKkKUKNwVscpVneq6WXGtfiMGwXpF8MfoGigE=");
var decrypted = privateKey.decrypt(ciphertext, 'RSA-OAEP');
document.getElementById("pt").innerHTML = "Decrypted: " + decrypted;
</script>
Note: I'd like to give credit to Topaco for their considerable help and original answer, which this one is based off of.
Related
Am having a password and pin as hex codes which is generated from JAVA. I need to decrypt this in javascript client side. Help me to resolve this.
First i have generated a public and private key using node forge in client side.
var keys = forge.pki.rsa.generateKeyPair(512);
forge.pki.publicKeyToPem(keys.publicKey)
Then i have sent that public key to a service. It returned an encrypted key and an encrypted data. To decrypt the data, first i need to decrypt the key which i got from the service.
var decrypted= keys.privateKey.decrypt(forge.util.decode64("M+v0Su2bzQPp20yvsVcySP+Z+iK2egV6hKJ6UNIubVPkVoOilhn+ywXDdm8LOW/37UimsB6reRm+XHR8uHZHJQ=="));
decrypted = forge.utils.bytesToHex(decrypted);
I have got the decrypted key now.
decrypted key - da019e4c07132376543b235e7f8a432c
Now i need to decrypt the data using this key with tripleDES algorithm. In service side DESede/ECB/NOPadding algorithm was used.
Data to be decrypted Hex- 717AAE5F33D06EFA
output should be 62261FFFFFFFFFFF
I generated an ECDH key pair, and get the public key from it. Using nodejs and the crypto library.
const ecdh = crypto.createECDH('secp384r1');
ecdh.generateKeys();
const publicKey = ecdh.getPublicKey('hex');
I'm implementing a client side library to encrypt data using this public key, the ECDH algorithm and the SubtleCrypto interface from WebCrypto.
To Accomplish this I have to import the public key (Generated with nodejs crypto), WebCrypto importKey method has some format options to do it, but I can get it to work with non of them. I noticed that jwk is more used than the others.
An example of a jwk is
{
kty: "EC",
crv: "P-256",
x: "kgR_PqO07L8sZOBbw6rvv7O_f7clqDeiE3WnMkb5EoI",
y: "djI-XqCqSyO9GFk_QT_stROMCAROIvU8KOORBgQUemE",
d: "5aPFSt0UFVXYGu-ZKyC9FQIUOAMmnjzdIwkxCMe3Iok",
ext: true,
}
So how can I parse my public key Into a jwk object. My public key looks like this:
04f8b2a6e9d2ffa424c3e7b6addf23112153920fd0209390da460f99e03bf8665052e72df4a0b7927381f1b026c98a3a2b348fdd10969875e6b0e86cb1f093a5fc07e49fbbbf091922ce71af17f4a79de03f6069836a7143b137be34451f162235
I don't have a direct answer for you but you may want to look at the https://github.com/PeculiarVentures/node-webcrypto-ossl which provides you a webcrypto interface in node. If you dont want to use it directly you can find the answer to your question in its JWK handling.
Maybe the key-encoder-library can help. Try to export as PEM and check if that is working. Consider to create your keys with the node-webcrypto-ossl-lib. The 'jwk'-format is a real help during dev. One can easily clone exported-keys like so :
cloneK = JSON.parse( JSON.stringify( exportedKey ) )
Facing an issue while creating SHA1 from javascript and java. The problem is both are different. It is used for validating the client request to web server. That means client send a based64 encoded security key to server and server regenerate the same key and equate both are same. Please find below code for generating secret keys in client and server.
Server
MessageDigest mDigest = null;
try {
mDigest = MessageDigest.getInstance("SHA1");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
String input = value1 + value1 + server_key;
byte[] result = mDigest.digest(input.getBytes());
String secret = Base64.encodeToString(result, Base64.NO_WRAP);
...
//comparison logic goes here
...
Client (java script)
var input = value1 + value2 + server_key;
//http://code.google.com/p/crypto-js/
var hash = CryptoJS.SHA1(input);
var encoded = base64Encode(hash.toString());
//WEB SERVICE INVOCATION FROM JAVASCRIPT GIES HERE.
The values value1, value1, server_key will be available in both client and server. The issue we are facing is, the SHA1 generated in both client and server is not matching. I understand the issue is in java its using getBytes() and in javascript using string value for generating SHA1. The CryptoJS.SHA1 does not support bytearray as parameter. We cannot change the server code as it is used by many client applications. Any help will be much appreciated.
In Java ->
byte[] result = mDigest.digest(input.getBytes());
and in JavaScript ->
var hash = CryptoJS.SHA1(input);.
I belief this is the problem. In java the parameter is a bytearray and output is also a bytearray. But in javascript the parameter is var (string) and return is also var (string). I 've also compared the output of CryptoJS.SHA1 with some online SHA1 generating tools. The comparison is true. I am not an expert in this area. If you can explain more, it will be more helpful.
I managed it to do in another way. My application is a cordova based application. So generated the sha1 and encoded it from java and objC and invoked it using cordova plugins.
I am struggling with SHA256 encoding.
There is a Python example but I don't understand it quite well.
Example (Python):
message = nonce + client_id + api_key
signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper()
Can somebody make a simple blueprint so I can work from there?
Crypto-js implements SHA256
If you include the library, you should be able to run the following (assuming 'message' and 'API_SECRET' are the same as the python code)
var signature = CryptoJS.HmacSHA256(message,API_SECRET).toString(CryptoJS.enc.Hex).toUpperCase();
Hi so lets assume that client-side has a key that is not transfered via the same channel as the encrypted data.
What I am trying to accomplish is to decrypt the result of Stanford Javascript Crypto Library (sjcl) in ruby. or for a generalisation in any other language that has a crypto library that has support for AES.
Here is what I am doing in javascript:
sjcl.encrypt('stack-password', 'overflow-secret')
And this is what I get in return:
{
"iv": "Tbn0mZxQcroWnq4g/Pm+Gg",
"v": 1,
"iter": 1000,
"ks": 128,
"ts": 64,
"mode": "ccm",
"adata": "",
"cipher": "aes",
"salt": "pMQh7m9Scds",
"ct": "H6JRpgSdEzKUw2qEO1+HwIzAdxGTgh0"
}
So what I'm actually asking is, which of these parameters I need(assuming the server already has the "stack-password" key) in order to decrypt the secret server-side, and which library should I use?
May be having AES decryption library is not enough?
The following can not be negotiated a head of time (or hard coded).
ct: cipher-text your encrypted data, obviously
iv: initialization vector, should be unique and not be reused with the same key for AES-CCM
salt: random, and is used to create the key from password with Pbkdf2
adata: additional authenticated data, is plain text data that you want to include but ensure that it has not been tampered when using AES-CCM. If you aren't ever going to include any data then you can ignore it (you would have had to pass it with the plaintext in sjcl).
The following you can negotiated a head of time (or hard coded), in fact you shouldn't plug these values in on the server encryption api, when transmitted unauthenticated and expect security. adata wouldn't be a bad place for v, iter, or ks if you wanted it to be changeable based on the client
iter: iterations for Pbkdf2, this just needs to be high enough to slow down bruteforce on your password needs to change with the speed of hardware in the future.
ks: keysize to know what size key to generate with Pbkdf2, needs to change with the amount of security in future
ts: tagsize to know what size authentication tag is part of your cipher text
cipher: If you will only support AES, then you can just assume.
mode: if you will only support AES-CCM than you can just assume.
v: If you will only support one version of sjcl in the future than you can just assume.
With ruby using the OpenSSL library seems like it could work as long as your OpenSSL supports AES-128-CCM puts OpenSSL::Cipher.ciphers to check. And it does support generating keys using pbkdf2, but you do need to use Sha256 digest to be compatible with sjcl, which is again dependent on your version of openssl.
For those coming here from Google, I managed to use the sjcl library to encrypt on Appcelerator's Titanium and decrypt on Ruby/Rails.
Encrypt (javascript):
var data = SJCL.encrypt('your key here',
'plain text',
{ mode: 'gcm',
iv: SJCL.random.randomWords(3, 0) });
The important bit is using a smaller IV.
Decrypt (ruby):
def self.decrypt(h)
h = HashWithIndifferentAccess.new(JSON.parse(h))
key = OpenSSL::PKCS5.pbkdf2_hmac('your key here', Base64.decode64(h[:salt]), 1000, h[:ks]/8, 'SHA256')
puts "Key: #{key.unpack('H*')}"
puts "Salt: #{Base64.decode64(h[:salt]).unpack('H*')}"
c = OpenSSL::Cipher.new("#{h[:cipher]}-#{h[:ks]}-#{h[:mode]}")
c.decrypt
c.key = key
c.iv = Base64.decode64(h[:iv])
puts "IV: #{Base64.decode64(h[:iv]).unpack('H*')}"
c.auth_data = ""
c.update(Base64.decode64(h[:ct]))
end
Alternatively, I wrote up a translation of SJCL into pure Ruby (at least for the CCM parts). This doesn't require updating OpenSSL, but it's a bit slower.
You can find it at https://github.com/mdp/sjcl_rb
Hope this helps