Encrypt with Cryptico.js, Decrypt with OpenSSL - javascript

I am creating a public/private key on the server, sending the key to the JavaScript client where it encrypts a users password. The client sends the password to the server, and the server uses the private key to decrypt it, but the password is coming back null. I have verified all values supporting the situation are correct, so it's something with the encryption/decryption specifically. Where am I going wrong?
Possibly, is cryptico.js not compatible with php openssl?
Library Info:
https://github.com/wwwtyro/cryptico
http://www.php.net/manual/en/function.openssl-pkey-new.php
Here are relevant code snippets:
PHP - create public/private key
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
// Create the private and public key
$res = openssl_pkey_new($config);
// Extract the private key from $res to $privateKey
openssl_pkey_export($res, $privateKey);
// Extract the public key from $res to $publicKey
$publicKey = openssl_pkey_get_details($res);
$publicKey = $publicKey["key"];
JavaScript - Client encrypts data with public key.
var xhr = new XMLHttpRequest();
var data = new FormData();
xhr.open('POST', '/signUp2.php');
data.append('user', User);
var encryptedPassword = cryptico.encrypt(password, localStorage["publicKey"]);
data.append('password', encryptedPassword.cipher);
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4 && xhr.status == 200)
{
var jsonArray = JSON.parse(xhr.responseText);
if(jsonArray[0] == "0")
{
alert("Account created. You may now sign in.");
}
else
alert("Error Code: " + jsonArray[0]);
}
}
xhr.send(data);
PHP - Server recieves encrypted password and attemps to decrypt unsuccessfully
openssl_private_decrypt($encryptedPassword, $decryptedPassword, $row[1]);

cryptico.js could work with openssl, but we have to modify it a bit.
it don't directly recognize the public key in pem format (which openssl use). we have to extract the 'n' and 'e' part of a public key in php side:
$key = openssl_pkey_new(array(
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
'digest_alg' => 'sha256'
));
$detail = openssl_pkey_get_details($key);
$n = base64_encode($detail['rsa']['n']);
$e = bin2hex($detail['rsa']['e']);
also, cryptico.js hardcoded the 'e' part of a public key (see definition of publicKeyFromString in api.js), so we need to fix this:
my.publicKeyFromString = function(string)
{
var tokens = string.split("|");
var N = my.b64to16(tokens[0]);
var E = tokens.length > 1 ? tokens[1] : "03";
var rsa = new RSAKey();
rsa.setPublic(N, E);
return rsa
}
now we are able to encrypt strings:
var publicKey = "{$n}|{$e}",
encrypted = cryptico.encrypt("plain text", publicKey);
job is not finished yet. the result of cryptico.encrypt is NOT simply encrypted by RSA. indeed, it was combined of two parts: an aes key encrypted by RSA, and the cipher of the plain text encrypted with that aes key by AES. if we only need RSA, we could modify my.encrypt:
my.encrypt = function(plaintext, publickeystring, signingkey)
{
var cipherblock = "";
try
{
var publickey = my.publicKeyFromString(publickeystring);
cipherblock += my.b16to64(publickey.encrypt(plaintext));
}
catch(err)
{
return {status: "Invalid public key"};
}
return {status: "success", cipher: cipherblock};
}
now we are able to decrypt the cipher with openssl:
$private = openssl_pkey_get_private("YOUR PRIVATE KEY STRING IN PEM");
// $encrypted is the result of cryptico.encrypt() in javascript side
openssl_private_decrypt(base64_decode($encrypted), $decrypted, $private);
// now $decrypted holds the decrypted plain text

Related

How do i get RSACryptoServiceProvider to verify a message using public key and signature

I generated a private and public key in javascript like this.
import crypto from "crypto";
/*export const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 2048,
});*/
const pair = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
export const privateKey = pair.privateKey.export({
type: "pkcs1",
format: "pem",
});
export const publicKey = pair.publicKey.export({
type: "pkcs1",
format: "pem",
});
Then i use the private key to create a signature for a jsonfile like this, and the public key to verify it before i return the signature.
//Lav signatur
const signate = crypto.createSign("SHA384");
signate.update(Buffer.from(licenseRelationship, "utf-8"));
const signature = signate.sign(privateKey, "hex");
const verifier = crypto.createVerify("SHA384");
// verificer signature, besked
verifier.update(Buffer.from(licenseRelationship, "utf-8"));
const verificationResult = verifier.verify(publicKey, signature, "hex");
This works perfectly, and then i return the json and the signature as a http response.
I recieve it in c# code and store the two components so im can use them later on request.
Upon request i fetch the two components and want to use the signature to check if the json has been tampered with.
I also has the public key in this code.
I do it like this.
string licenseRelationshipJson = licenseRelationshipDAO.getLicenseRelationshipWithoutSignatureAsJson(licenseRelationship);
byte[] signature = Encoding.UTF8.GetBytes(licenseRelationship.signature);
byte[] licenseRelationshipJsonAsArray = Encoding.UTF8.GetBytes(licenseRelationshipJson);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
result = rsa.VerifyData(licenseRelationshipJsonAsArray, signature,
HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
if (result)
{
log.write("Message verified ", null);
} else
{
log.write("Message not Verified ", null);
}
All debug code and exception handling removed.
I'm a crypto virgin, and am trying to understand this. But i must have misunderstood something serious.
I have the public key as a string (not base64 encoded)
Ive checked the json, and it is the exact same bytes when signed in Javascript as when being verified in c#
The public key is not used in this process. That has to be wrong i think ?
How do i get the public key into the RWACryptoServiceProvider ?
Im sure im using RWACryptoServiceProvider wrong.
EDIT....:
Ive tried this instead, but still to no avail.
string licenseRelationshipJson = licenseRelationshipDAO.getLicenseRelationshipWithoutSignatureAsJson(licenseRelationship);
byte[] signature = Encoding.UTF8.GetBytes(licenseRelationship.signature);
byte[] licenseRelationshipJsonAsArray = Encoding.UTF8.GetBytes(licenseRelationshipJson);
byte[] asBytes = Encoding.ASCII.GetBytes(DataStorage.Instance.PUBLIC_KEY);
char[] publicKeyAsArray = Encoding.ASCII.GetChars(asBytes);
ReadOnlySpan<char> publicKeyChars = publicKeyAsArray;
RSA rsa = RSA.Create();
try
{
rsa.ImportFromPem(publicKeyChars);
result = rsa.VerifyData(licenseRelationshipJsonAsArray, signature, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
} catch (CryptographicException cex)
{
log.write("Something went wrong with the crypto verification process", cex);
}
.
.
.
Thankyou for your time.

AES encryption method in NodeJS similar to C sharp function

I have a function written in C#. Basically the function is used to generate a token on the basis of parameters like text and key.
public string Encrypt(string input, string key) {
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncrptArray = UTF8Encoding.UTF8.GetBytes(input);
Aes kgen = Aes.Create("AES");
kgen.Mode = CipherMode.ECB;
kgen.Key = keyArray;
ICryptoTransform cTransform = kgen.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncrptArray, 0, toEncrptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
I'm trying to search any same alternative for the above function in NodeJS or run this function inside the NodeJS script through any compiler.
I have tried the crypto-js module in NodeJS but got a different token string. Please suggest the alternative function or any idea about running this function inside the NodeJS script.
My Recent code in NodeJS :
First Method :
var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt("<input>", "<key>").toString();
Second Method :
var crypto = require('crypto'),
algorithm = 'aes-256-ctr',
password = '<key>';
function encrypt(text){
var cipher = crypto.createCipher(algorithm,password)
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
Both the method is giving different token if compared to C# function.
The AES algorithm used in the C# code is AES 128-bit in ECB mode.
We can perform the same encryption in Node.js (and decrypt as well if we wish), using the following code:
Node.js Code
const crypto = require("crypto");
function encrypt(plainText, key, outputEncoding = "base64") {
const cipher = crypto.createCipheriv("aes-128-ecb", key, null);
let encrypted = cipher.update(plainText, 'utf8', outputEncoding)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
function decrypt(cipherText, key, outputEncoding = "utf8") {
const cipher = crypto.createDecipheriv("aes-128-ecb", key, null);
let encrypted = cipher.update(cipherText)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
const KEY = Buffer.from("abcdefghijklmnop", "utf8");
console.log("Key length (bits):", KEY.length * 8);
const encrypted = encrypt("hello world", KEY, "base64");
console.log("Encrypted string (base64):", encrypted);
// And if we wish to decrypt as well:
const decrypted = decrypt(Buffer.from(encrypted, "base64"), KEY, "utf8")
console.log("Decrypted string:", decrypted);
C# Code
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
Console.WriteLine("Result: " + Encrypt("hello world", "abcdefghijklmnop"));
}
public static string Encrypt(string input, string key) {
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncrptArray = UTF8Encoding.UTF8.GetBytes(input);
Aes kgen = Aes.Create("AES");
kgen.Mode = CipherMode.ECB;
kgen.Key = keyArray;
ICryptoTransform cTransform = kgen.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncrptArray, 0, toEncrptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
}
The results for the encryption (with plaintext and key as above) are:
.Net: f7sSBDV0N6MOpRJLpSJL0w==
Node.js: f7sSBDV0N6MOpRJLpSJL0w==
Obviously we must not use this key in production!

Different behaviors from Decryption method in java

i am using decryption alogirthm RSA with public and private keys from certification .
var encrypt = new JSEncrypt();
var publicKey = "example";
encrypt.setPublicKey(publicKey);
var data = encrypt.encrypt(value);
console.log(data);
return data;
public static String getDecrypted(String data, String Key)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher cipher = Cipher.getInstance("RSA");
PrivateKey pk = KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(Key.getBytes())));
cipher.init(Cipher.DECRYPT_MODE, pk);
// byte[] encryptedbytes =
// cipher.doFinal(Base64.encodeBase64(data.getBytes()));
return new String(cipher.doFinal(Base64.decodeBase64(data)));
}
i am using front end encryption and in main method encryption . the encrypted values from two sides are getting correctly . but when i call it from web
i get another values like that
EAQ�žÃqÈ›#Á¢éz¡?�4zsHD-U€�
KÉ¢a`Õ³=jö`›=šúFhU;••˜ü®2¿¶žñÛ¤lÉê×)§?]¾–`n_üÙ&1ï)ðeÈž‹x¯ø¬#;ýp& Ê*í~ý¾´çVõF¯±ë©yṉ̃©w_f'úH⬒#™G™|¦ý¹j"Ìç8=ŽRÉž[££4™s#àâ
and the value at the end

How to decrypt a file in CryptoJS , encrypted by JAVA with AES

enter image description hereI want to encrypted JPG file in Java with AES, but I don't know how to decrypt the JPG file in javascript. Anyone has better idea?
this is my java code。
`private static void EncFile(File srcFile, File encFile) throws Exception
{
if(!srcFile.exists()){
System.out.println("source file not exixt");
return;
}//
if(!encFile.exists()){
System.out.println("encrypt file created");
encFile.createNewFile();
}
byte[] bytes = new byte[1024*8];
String key = "1234567812345678";
String iv = "1234567812345678";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
InputStream fis = new FileInputStream(srcFile);
// CipherInputStream cin = new CipherInputStream(fis, cipher);
OutputStream fos = new FileOutputStream(encFile);
while ((dataOfFile = fis.read(bytes)) >0) {
byte[] encrypted = cipher.doFinal(bytes);
fos.write(encrypted,0,dataOfFile);
}
fis.close();
fos.flush();
fos.close();
}`
this my javascipt code, I have used CryptoJS and Decrypt does
var key = CryptoJS.enc.Latin1.parse('1234567812345678');
var iv = CryptoJS.enc.Latin1.parse('1234567812345678');
var url = "http://192.168.0.103/show3d_test/test/CR4/E1234.png";
var xhr = new XMLHttpRequest();
xhr.open("GET",url,true);
xhr.responseType = "arraybuffer";
xhr.onload = function() {
if(xhr.readyState ==4){
if (xhr.status == 200){
process(xhr.response,key);
}
}
}
xhr.send();
function process(buffer,key) {
var view = new Uint8Array(buffer);
var contentWA = CryptoJS.enc.u8array.parse(view);
var dcBase64String = contentWA.toString(CryptoJS.enc.Base64);
var decrypted = CryptoJS.AES.decrypt(dcBase64String,key,
{iv:iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.NoPadding});
var d64 = decrypted.toString(CryptoJS.enc.Base64);
var img = new Image;
img.src = "data:image/png;base64,"+d64;
document.body.append(img);
} `
Anyone know how to do that? I've seen so much example about CryptoJS - Java encrypt/decrypt but most of them use hardcoded IV/key, or just send IV/key from cryptoJS side to Java side. All I have is a passphrase, just like what this site do!
Not sure what the exact question is but this should help.
A general and secure method for an IV is to create one with a CSPRNG (random bytes) and prefix the encrypted data with the IV so it will be available for decryption. The IV does not need to be secret.
When using "AES/CBC/NoPadding" the input must be an exact multiple of the block size (16-bytes for AES). Generally PKCS#7 (PKCS#5) padding is specified so there are no limits on the data length to be encrypted.

Best approch to decode the PKCS12 file and get the encrypted private key from it using JavaScript

Please suggest any idea to decode the PKCS12 file and get the encrypted private key from it using JavaScript. I know that it can be done very easily using Java Keytool command and Java Security package. But I want it to be done by Java Script. Bellow is my actual requirement.
I have a ".p12" extention file which is one of the formats of pkcs12.
It should be decoded first and need to trace out the decoded file where exactly the encrypted Private key is placed.
Need to get that encrypted Private key and Decrypt it and send it to the receiver.
And all this Should be done only in JAVASCRIPT.
I think this might be what you are looking for:
"A native implementation of TLS (and various other cryptographic tools) in JavaScript."
https://github.com/digitalbazaar/forge#pkcs12
It sounds like this example is close:
// decode p12 from base64
var p12Der = forge.util.decode64(p12b64);
// get p12 as ASN.1 object
var p12Asn1 = forge.asn1.fromDer(p12Der);
// decrypt p12
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password');
// look at pkcs12.safeContents
// generate p12, base64 encode
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(
privateKey, certificateChain, 'password');
var p12Der = forge.asn1.ToDer(p12Asn1).getBytes();
var p12b64 = forge.util.encode64(p12Der);
Rgds....Hoonto/Matt
This will work Perfectly
// get p12 as ASN.1 object
var p12Asn1 = forge.asn1.fromDer(buffer);
// decrypt p12 using the password 'password'
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password);
// get bags by type
var certBags = p12.getBags({bagType: forge.pki.oids.certBag});
var pkeyBags = p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag});
// fetching certBag
var certBag = certBags[forge.pki.oids.certBag][0];
// fetching keyBag
var keybag = pkeyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0];
// generate pem from private key
var privateKeyPem = forge.pki.privateKeyToPem(keybag.key);
// generate pem from cert
var certificate = forge.pki.certificateToPem(certBag.cert);
Thanks to the examples from #Ujjawal and #hoonto I was able to get the following working well.
const decodePKCS12 = (
file // Dom File object
) => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = evt => {
try {
const binary = evt && evt.target ? evt.target.result : null
if (!binary) {
reject(new Error('No file data'))
}
const p12Asn1 = asn1.fromDer(binary)
const p12 = pkcs12.pkcs12FromAsn1(p12Asn1)
const certBags = p12.getBags({bagType: pki.oids.certBag})
const pkeyBags = p12.getBags({bagType: pki.oids.pkcs8ShroudedKeyBag})
const certBag = certBags[pki.oids.certBag][0]
const keybag = pkeyBags[pki.oids.pkcs8ShroudedKeyBag][0]
const certificate = pki.certificateToPem(certBag.cert)
const privateKey = pki.privateKeyToPem(keybag.key)
resolve({certificate, privateKey})
} catch (e) {
reject(e)
}
}
reader.onerror = reject
reader.readAsBinaryString(file)
})
}

Categories

Resources