This is the function used to encrypt in java
public static String encryptionFunction(String fieldValue, String pemFileLocation) {
try {
// Read key from file
String strKeyPEM = "";
BufferedReader br = new BufferedReader(new FileReader(pemFileLocation));
String line;
while ((line = br.readLine()) != null) {
strKeyPEM += line + "\n";
}
br.close();
String publicKeyPEM = strKeyPEM;
System.out.println(publicKeyPEM);
publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");;
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
// byte[] encoded = Base64.decode(publicKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pubKey = (PublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(fieldValue.getBytes());
if (cipherData == null) {
return null;
}
int len = cipherData.length;
String str = "";
for (int i = 0; i < len; i++) {
if ((cipherData[i] & 0xFF) < 16) {
str = str + "0" + java.lang.Integer.toHexString(cipherData[i] & 0xFF);
} else {
str = str + java.lang.Integer.toHexString(cipherData[i] & 0xFF);
}
}
return str.trim();
} catch (Exception e) {
System.out.println("oops2");
System.out.println(e);
}
return null;
}
I want the equivalent of this in javascript/Nodejs, i tried this:
import * as NodeRSA from 'node-rsa';
private encryptionFunction(fieldValue: string , pemkey: string) : string {
const rsa = new NodeRSA(pemkey);
const encrypted= rsa.encrypt(fieldValue , 'hex')
return encrypted
}
But the output size of both functions is the same, but apparently the encryption type is wrong.
Node-RSA applies OAEP (here) as padding by default, so the PKCS#1 v1.5 padding used in the Java code must be explicitly specified. This has to be added after key import and before encryption:
rsa.setOptions({ encryptionScheme: 'pkcs1' });
Alternatively, the padding can be specified directly during key import:
const rsa = new NodeRSA(pemkey, { encryptionScheme: 'pkcs1' });
With this change, both codes are functionally identical.
Regarding testing: Keep in mind that RSA encryption is not deterministic, i.e. given the same input (key, plaintext), each encryption provides a different ciphertext. Therefore, the ciphertexts of both (functionally identical) codes will be different even if the input is identical. So this is not a bug, but the expected behavior.
How then can the equivalence of both codes be proved? E.g. by decrypting both ciphertexts with the same code/tool.
I am trying to convert one JavaScript encryption function in C#. But not getting the valid output. Can someone help me with this issue.
Below is my JavaScript function for encryption
function encryptPassword()
{
var password="samplepassword"; mod="ce33b5600160ba9354a0e56ee3e43369e9a824e0f88e20ad52bbde015cc8c8fed57aa2d65c4eb13dc099f38718fcbc471e60bb4d82a5e05b6a64c5dc8d2e17ca44c205a6c54540d4884285808e829043b2f11838dc5d603750616bf5fd711d810b50f7a468e31d0cfc5b70e6a72fe887a2e26db44c3868a86febb5e4c5f6c27000b202a0460488db3eac48f1ee80e7ca6bb8a9af2b985c28aa25ecdc74e485abd20311c21add507e8c65c3d11d743ebbd76c44933bb68981e1171376d1ddf33607fa2116cb747f0c3f238bae5b01878004157cfef9c8cdd697ee39759625f84abd89469a8b8cd9eabb2e79fd9269ab4e62670d6ec8b5b1f6d986385b2394bfdb";
var rsa = new RSAKey();
rsa.setPublic(mod, "10001");
var res = rsa.encrypt(password);
if(res) {
document.getElementById('password').value=res;
return true;
}
else
{
return false;
}
}
Below is my C# implementation for the same. But somehow I am not getting the proper output. C# generated output is not validated at server side.
C# code
public static string EncryptRSAx(string public_keyHex, uint exp, string data)
{
byte[] bytes = new byte[public_keyHex.Length / 2];
for (int i = 0; i < public_keyHex.Length - 1; i += 2)
{
bytes[i / 2] = byte.Parse(public_keyHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
}
string public_key = Convert.ToBase64String(bytes);
return RSAEncrypt(public_key, Convert.ToBase64String(BitConverter.GetBytes(exp)), data);
}
public static string RSAEncrypt(string public_key, string exponent, string data)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
//rsa.FromXmlString()
rsa.FromXmlString(String.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>", public_key, exponent));
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data);
byte[] cipherbytes = rsa.Encrypt(plainbytes,false);
return Convert.ToBase64String(cipherbytes);
}
I have a simple node.js script
var text = "Hello!";
var serverSeed = "d8818b38a14e7461e87301ad4b9809b558bcbca816b650cd470452e018ada255";
var crypto = require('crypto');
var hash = crypto.createHmac('sha512', serverSeed).update(text).digest('hex');
console.log(hash);
I also have the C# program
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
public static void Main()
{
var serverSeed = StringToByteArray("d8818b38a14e7461e87301ad4b9809b558bcbca816b650cd470452e018ada255");
using (var sha = new HMACSHA512(serverSeed))
{
var hash = sha.ComputeHash(Encoding.ASCII.GetBytes("Hello!"));
Console.WriteLine(ByteArrayToString(hash));
}
}
}
(runable version here)
I get from the node.js program
99e3b20acaa9c7674f074da950945ee897876b0afc02121d5a89fa581081465f3e01a084e9b05bed729b7fbdc1d485fb38af7d6f501cbc258b6c66add54410ba
And from the C# program
73250817a927f394b0912afcece47b8c12aeaed31892c64116ae9dd0d407f6e31d5c062d65f68a3cae09a8acb14a7cef1f6afd99f5a22f2b73e46a991fcd079a
What am I doing wrong to cause this difference?
Your C# code is converting the hex characters in your seed to a byte array based on the what the characters represent in hexadecimal format.
But your node code is passing the seed as a string which is converting the characters to a byte.
So for example, your C# code is converting a to a byte with the value of 10 but your node code would be converting a to a byte with the value of 97
Your node code either needs to convert the hex in your string to a Buffer based on their hex values as you are doing in C#.
var text = "Hello!";
var serverSeed = "d8818b38a14e7461e87301ad4b9809b558bcbca816b650cd470452e018ada255";
var crypto = require('crypto');
var buff = new Buffer(seed, "hex")
var hash = crypto.createHmac('sha512', buff).update(text).digest('hex');
console.log(hash);
Or in C# instead of converting hex to bytes you can get a byte array representing the actually characters the seed using GetBytes from a System.Text.Encoding instance.
var serverSeed = Encoding.ASCII.GetBytes("d8818b38a14e7461e87301ad4b9809b558bcbca816b650cd470452e018ada255");
using (var sha = new HMACSHA512(serverSeed))
{
var hash = sha.ComputeHash(Encoding.ASCII.GetBytes("Hello!"));
Console.WriteLine(ByteArrayToString(hash));
}
Most likely you intended to pass the serverSeed as a buffer in the node.js code.
Here is my code:
private void send_char_0(string R, string G, string B)
{
string r = R;
string g = G;
string b = B;
string strData = null;
int i = 0;
byte[] data_array = new byte[3]{0xff,0xef,0xff};
}
I have brought hexvalues in string R,G,B respectively but when i pass them
byte[] data_array = new byte[3]{R,G,B}; -> error string cannot be converted to byte.
So i tried to convert dataarray[0] = Convert.ToByte(R) i.e Convert.ToByte(0xff)--> error Input string is not in proper format as 0xff . needs to have "ff" but i need to pass it as "oxff" to serial port.
Anyone can help me
You are passing strings into array of bytes.
Try this:
private void send_char_0(string R, string G, string B)
{
byte r = byte.Parse(R,NumberStyles.HexNumber);
byte g = byte.Parse(G,NumberStyles.HexNumber);
byte b = byte.Parse(B,NumberStyles.HexNumber);
byte[] data_array = new byte[3]{r,g,b};
}
You probably will need to add some check if this data is correct, as it cames from user,
I am using RSA in javascript from: http://www-cs-students.stanford.edu/~tjw/jsbn/
And on their demo page, it is able to generate the keys required: http://www-cs-students.stanford.edu/~tjw/jsbn/rsa2.html
But what I don't understand, is how to turn their key, which is a few variables, of hex strings, into a string that looks like a private/public key string.
Their output looks like this...
Modulus (hex):
a32464be9bef16a6186a7f29d5ebc3223346faab91ea10cc00e68ba26322a1b0
3dc3e1ec61832fca37ed84018db73ae6b79bd8f3fa2945c8606766402658d0c1
Public exponent (hex, F4=0x10001):
10001
Private exponent (hex):
c3f5730d81402e7453df97df2895884e0c49b5cf5ff54737c3dd28dc6537b3fd
8b0eb2fd82148ebbf81fe16128ec1ebf39fd9a6e62d42aad245b172f4ed8661
P (hex):
f542cdc91f73747ecc20076962a2ed91749b8e0af66693ba6f67dd92f99b1533
Q (hex):
aa491917d8b05a75db7a5c1f6b592b0f0a9bb30a530cbef44ae233b9bf3d5a3b
D mod (P-1) (hex):
e5bfbea639201e70e926d7ca90ebaf4022cbd533cfbe2784edf78e48b029e6a1
D mod (Q-1) (hex):
3e3e17d8fa9083903ed83be21427f4b03bcd6ba523742e3c373ef56f38b2e14f
1/Q mod P (hex):
d93a8828e23458c2115fc1dd003274485af1483e8ec35866d5cffd214c5f853e
I expect a private key to look something like this...
-----BEGIN RSA PRIVATE KEY-----
MIIBOQIBAAJBALH5w2R5Zl3hHoH7zDF6i5IbO7W1Ry9bT2bxTy2sJa7mZC+p3rQG
YNrX+M/KuOUuVqFaohrWLwU28+VlFjFHG5MCAwEAAQJAFZCi+Viwa62saamd+1zS
7pg4KvNVNcrFmz6gDnOueTujcBdaNfxOzWy39SxSOtPe62qYHPculci/QiJfLvOf
MQIhAOqxj69QPRqervf6ARMI1zV0+UAGA1tWgOeU7NH0U9vLAiEAwiIJu+986PKT
qmjAKDFx3OJxUuEay8kJ5apDjC6s1lkCIBVRdazGDBbb7SbHRcu11N6dNnrTUQC9
9c2TYIOdvvRLAiB7bbDKsKW2ZiTEv/0MkQNX8REkJMMothV41BxGUJbLYQIgF/yA
54gqfRtj3aPB6lDETMOZbZIWgNpn8hU2kFGdlIs=
-----END RSA PRIVATE KEY-----
The private and public keys you are familiar with are in a format called PEM. PEM refers to the header and footer wrapping base64 encoded data.
The encoded binary data is in the DER (Distinguished Encoding Rules) format of ASN.1 (Abstract Syntax Notation One).
Here's a javascript ASN.1 decoder.
http://lapo.it/asn1js/
The public and private keys contain the modulus and either the public or private exponent respectively.
The following code came from a couple authors (listed in the comments), compiled on Ohloh Code (http://code.ohloh.net/file?fid=gxO4OHIDEgc0cAHG4K2iptOVOUY&cid=b0rvFixqcq4&s=&fp=285256&mp=&projSelected=true#L0). All credit due to them for their hard work. But the compilation did the trick for me. Add this as a .js library and then you can call it from your main routine like this:
publicPem = publicPEM();
privatePemUnencrypted = privatePEM(); //you will probably want to encrypt this
The output is in PEM format.
Codez:
//From git://github.com/titanous/pem-js.gitmaster
var ASNIntValue, ASNLength, int2hex;
function privatePEM() {
var encoded;
encoded = '020100';
encoded += ASNIntValue(this.n, true);
encoded += ASNIntValue(this.e, false);
encoded += ASNIntValue(this.d, false);
encoded += ASNIntValue(this.p, true);
encoded += ASNIntValue(this.q, true);
encoded += ASNIntValue(this.dmp1, true);
encoded += ASNIntValue(this.dmq1, false);
encoded += ASNIntValue(this.coeff, false);
encoded = '30' + ASNLength(encoded) + encoded;
return "-----BEGIN RSA PRIVATE KEY-----\n" + encode64(chars_from_hex(encoded)) + "\n-----END RSA PRIVATE KEY-----";
};
function publicPEM() {
var encoded;
encoded = ASNIntValue(this.n, true);
encoded += ASNIntValue(this.e, false);
encoded = '30' + ASNLength(encoded) + encoded;
encoded = '03' + ASNLength(encoded, 1) + '00' + encoded;
encoded = '300d06092a864886f70d0101010500' + encoded;
encoded = '30' + ASNLength(encoded) + encoded;
return "-----BEGIN PUBLIC KEY-----\n" + encode64(chars_from_hex(encoded)) + "\n-----END PUBLIC KEY-----";
};
RSAKey.prototype.parsePEM = function(pem) {
pem = ASN1.decode(Base64.unarmor(pem)).sub;
return this.setPrivateEx(pem[1].content(), pem[2].content(), pem[3].content(), pem[4].content(), pem[5].content(), pem[6].content(), pem[7].content(), pem[8].content());
};
ASNIntValue = function(integer, nullPrefixed) {
integer = int2hex(integer);
if (nullPrefixed) {
integer = '00' + integer;
}
return '02' + ASNLength(integer) + integer;
};
ASNLength = function(content, extra) {
var length;
if (!(typeof extra !== "undefined" && extra !== null)) {
extra = 0;
}
length = (content.length / 2) + extra;
if (length > 127) {
length = int2hex(length);
return int2hex(0x80 + length.length / 2) + length;
} else {
return int2hex(length);
}
};
int2hex = function(integer) {
integer = integer.toString(16);
if (integer.length % 2 !== 0) {
integer = '0' + integer;
}
return integer;
};
/* CryptoMX Tools - Base64 encoder/decoder
* http://www.java2s.com/Code/JavaScriptDemo/Base64EncodingDecoding.htm
*
* Copyright (C) 2004 - 2006 Derek Buitenhuis
* Modified February 2009 by TimStamp.co.uk
* GPL v2 Licensed
*/
function encode64(a){a=a.replace(/\0*$/g,"");var b="",d,e,g="",h,i,f="",c=0;do{d=a.charCodeAt(c++);e=a.charCodeAt(c++);g=a.charCodeAt(c++);h=d>>2;d=(d&3)<<4|e>>4;i=(e&15)<<2|g>>6;f=g&63;if(isNaN(e))i=f=64;else if(isNaN(g))f=64;b=b+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(i)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)}while(c<
a.length);a="";b=b.split("");for(c=0;c<b.length;c++){if(c%64==0&&c>0)a+="\n";a+=b[c]}b.join();b=a%4;for(c=0;c<b;c++)a+="=";return a}
function decode64(a){var b="",d,e,g="",h,i="",f=0;a=a.replace(/[^A-Za-z0-9\+\/\=\/n]/g,"");do{d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(f++));e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(f++));h="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(f++));i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(f++));d=d<<2|e>>4;e=(e&15)<<4|h>>2;g=(h&3)<<
6|i;b+=String.fromCharCode(d);if(h!=64)b+=String.fromCharCode(e);if(i!=64)b+=String.fromCharCode(g)}while(f<a.length);return b=b.replace(/\0*$/g,"")};
/* JavaScript ASCII Converter
* http://www.vortex.prodigynet.co.uk/misc/ascii_conv.html
*
* TPO 2001/2004
* Modified Feb 2009 by Tim Stamp (timstamp.co.uk)
* License Unknown
*/
function chars_from_hex(a){var c="";a=a.replace(/^(0x)?/g,"");a=a.replace(/[^A-Fa-f0-9]/g,"");a=a.split("");for(var b=0;b<a.length;b+=2)c+=String.fromCharCode(parseInt(a[b]+""+a[b+1],16));return c};
Using the link suggested by #borkencode (http://lapo.it/asn1js/) I have been able to successfully extract all the components of the public key, and also the relevant components from private keys.
Code to test extraction of numerical portions of keys
// copy and paste into console whilst on `http://lapo.it/asn1js/`
// so that dependancies are met
var getParts, pri, pub;
getParts = function(key) {
var end, current, output, crypt, slice, sa, so, start, tree, _i, _len;
// strip out the BEGIN/END tags from the input keys
crypt = key.replace(/^-.+/mg, '');
// decode the input text into ASN1 object
tree = ASN1.decode(Base64.decode(crypt));
// set root object based on type of key
if (key.match(/PUBLIC KEY-/)) {
root = tree.sub[1].sub[0].sub;
} else if (key.match(/PRIVATE KEY-/)) {
root = tree.sub;
} else {
console.error("Not happening");
return;
}
// initialize empty array to populate with results
output = [];
// loop through the root ASN1 object
for (_i = 0, _len = root.length; _i < _len; _i++) {
// get the current object
current = root[_i];
// set the start and end positions in the stream
start = current.stream.pos + current.header;
end = start + current.length;
// cut the required compnent out of the stream
slice = current.stream.enc.slice(start, end);
// format the slice in HEX, joining as string
// and replacing leading `00`s
str = slice.map(function(i) {
return ("0" + i.toString(16)).replace(/.(..)/, "$1");
}).join('').replace(/^(00)+/, '');
// add to output array
output.push(str);
}
// send the results!
return output;
};
pri = "-----BEGIN RSA PRIVATE KEY-----\n"+
"MIIBOgIBAAJBAMpZrx0gTluJEu6+fop1e60lwbnlBD6kHvoRx85GBhUgD8SQknjc\n"+
"LcU2qqM/pV9ZX8MV8x49h2mzrmRyH7kDmpcCAwEAAQJAYf2GYMt5Rrids4IKk5CL\n"+
"IPFs3FH8eT1PRvh/UvP0FBwDMZu/Q4m+3PNTM3ARQhFuCvWgCalMmZkyVx0HYRLe\n"+
"4QIhAOaaQm+b/bSoHqolvVTcyfBL09rrLFZhgGkETX3R6cVRAiEA4KLdUm97YBxP\n"+
"T6/jkn/P7K8SUWEO9o9u8Bif1UKQB2cCIETqoSQ92EqfW9q5wKWV/nvkDYKFehCu\n"+
"vvOjp40MqPKhAiA2sPBZpbLQD5Rvvk8V1/Bzm5xGG+9csEc+RYCEl5QheQIhAKgi\n"+
"Xb3zY9lqtpX/mgTIrW6RPB3GocviJOibqtpfNxRU\n"+
"-----END RSA PRIVATE KEY-----";
pub = "-----BEGIN PUBLIC KEY-----\n"+
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMpZrx0gTluJEu6+fop1e60lwbnlBD6k\n"+
"HvoRx85GBhUgD8SQknjcLcU2qqM/pV9ZX8MV8x49h2mzrmRyH7kDmpcCAwEAAQ==\n"+
"-----END PUBLIC KEY-----";
console.dir(getParts(pri));
console.dir(getParts(pub));
Output to console:
0: ""
1: "ca59af1d204e5b8912eebe7...d8769b3ae64721fb9039a97"
2: "010001"
3: "61fd8660cb7946b89db3820...94c999932571d076112dee1"
4: "e69a426f9bfdb4a81eaa25b...c56618069044d7dd1e9c551"
5: "e0a2dd526f7b601c4f4fafe...ef68f6ef0189fd542900767"
6: "44eaa1243dd84a9f5bdab9c...a10aebef3a3a78d0ca8f2a1"
7: "36b0f059a5b2d00f946fbe4...f5cb0473e45808497942179"
8: "a8225dbdf363d96ab695ff9...1cbe224e89baada5f371454"
------------------------------------------------------
0: "ca59af1d204e5b8912eebe7...d8769b3ae64721fb9039a97"
1: "010001"
I have tested the values, using them as inputs to encrypt, and decrypt messages with my javascript library. What I really want to be able to do now, is to create the .pem and .pub files by going the other way, from numbers, to formatted text.
The closest I have found so far, is a PHP function, which I might translate to javascript. Details here: http://pumka.net/2009/12/19/reading-writing-and-converting-rsa-keys-in-pem-der-publickeyblob-and-privatekeyblob-formats/
//Encode key sequence
$modulus = new ASNValue(ASNValue::TAG_INTEGER);
$modulus->SetIntBuffer($Modulus);
$publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
$publicExponent->SetInt($PublicExponent);
$keySequenceItems = array($modulus, $publicExponent);
$keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
$keySequence->SetSequence($keySequenceItems);
//Encode bit string
$bitStringValue = $keySequence->Encode();
$bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte
$bitString = new ASNValue(ASNValue::TAG_BITSTRING);
$bitString->Value = $bitStringValue;
//Encode body
$bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode();
$body = new ASNValue(ASNValue::TAG_SEQUENCE);
$body->Value = $bodyValue;
//Get DER encoded public key:
$PublicDER = $body->Encode();
For answer to your question, please have a look at the RSA algorithm for the actual formulae . For the complexity part, its better to leave the transformation to the JS
In case it helps, I used this code for my application and it worked wonders :)