How to verify with PHP signature genrerated by cryptico.js - javascript

I try to sign messages in javascript before sending to a PHP application.
The PHP application must check the signature to be sure it's not false.
In javascript I use cryptico.js.
This is the js function for signing messages
var sign = function(passphrase, text) {
signingkey = cryptico.generateRSAKey(passphrase, 2048);
signString = cryptico.b16to64(signingkey.signString(text, "sha256"));
return signString;
}
This is the function for getting the public key:
var getPublicKey = function(passphrase) {
var rsaKey = cryptico.generateRSAKey(passphrase, 2048);
return = cryptico.publicKeyString(rsaKey);
}
For example, for the message "message" and the passphrase "test2" the public key and signature are
qH/J3/gvF/h5U02uPyC9Qzn/hHEV5DzB9nFfqk5zbQqHdInVe4sfL+npa+4fjLGrBU30Iuvcr+o9paEjzpH5dY48cq6JHqz1RyJ0CQIc2Jr5+sS4eL1ZIjxWlyN1pKMR+4aE2rlDAad56Ad1cytiaHuVvyK/gdtbKiuGroSQhJ1EVfZ60m3NIqnqmpi5Zdsnmzny4VH/d66BcGXxGaGaUaqFn0WTypuwIMZMMtzZEK7peKoaW4H4rfkfdrKcD8AaT+z9v5lLGkTl0NcZZ4LN9sSUzsHNfyAFK6cSXo/73z0tDAlGb5K+yWV6UHoYW1rcoIsxlNRZM6/6FYgMXbbfow==
XbF4O6v6oadEQGtdpQ7d54Q2JB9/ZEXEUH3S1FMn4E/PSqk7HLXjG4tNfuiUBa5eS8kYV49gwC8Yr+mn6YUAHt+K9lHPSsmltWoiHNOaas4aqai9nlyeft4TYYhP+GYbQfw+3n2TcO39s6M0vw0m0a8AX9JfF02JwCUhP4bu4dzG6Bl5dj000TbUkric14Jyurp8OHmmMvKW62TvXPhNOW39+wS1Qkfn9Bxmzi8UEVSVe3wP45JWZNgmgeGnpubDhD05FJEDErfVtZ/DRKD81q5YRd4X4cCkeDPDcJLgKW1jkCsA7yBqESXPDSkkrVUM06A9qMFUwk4mRI88fZ8ryQ==
I'm asking me how to verify it in php?
I tryed something like:
$rsa = new Crypt_RSA();
$rsa->loadKey('qH/J3/gvF/h5U02uPyC9Qzn/hHEV5DzB9nFfqk5zbQqHdInVe4sfL+npa+4fjLGrBU30Iuvcr+o9paEjzpH5dY48cq6JHqz1RyJ0CQIc2Jr5+sS4eL1ZIjxWlyN1pKMR+4aE2rlDAad56Ad1cytiaHuVvyK/gdtbKiuGroSQhJ1EVfZ60m3NIqnqmpi5Zdsnmzny4VH/d66BcGXxGaGaUaqFn0WTypuwIMZMMtzZEK7peKoaW4H4rfkfdrKcD8AaT+z9v5lLGkTl0NcZZ4LN9sSUzsHNfyAFK6cSXo/73z0tDAlGb5K+yWV6UHoYW1rcoIsxlNRZM6/6FYgMXbbfow=='); // public key
echo $rsa->verify('message', 'XbF4O6v6oadEQGtdpQ7d54Q2JB9/ZEXEUH3S1FMn4E/PSqk7HLXjG4tNfuiUBa5eS8kYV49gwC8Yr+mn6YUAHt+K9lHPSsmltWoiHNOaas4aqai9nlyeft4TYYhP+GYbQfw+3n2TcO39s6M0vw0m0a8AX9JfF02JwCUhP4bu4dzG6Bl5dj000TbUkric14Jyurp8OHmmMvKW62TvXPhNOW39+wS1Qkfn9Bxmzi8UEVSVe3wP45JWZNgmgeGnpubDhD05FJEDErfVtZ/DRKD81q5YRd4X4cCkeDPDcJLgKW1jkCsA7yBqESXPDSkkrVUM06A9qMFUwk4mRI88fZ8ryQ==') ? 'verified' : 'unverified';
I think the signature and/or public key are not formated correctly for php. Any idea?
Thank you in advance,
[EDIT]
I'm not sure the signature is correct. If I use the js function cryptico.b64to16(signature), the signature will be somethink like :
5db1783babfaa1a744406b5da50edde78436241f7f6445c4507dd2d45327e04fcf4aa93b1cb5e31b8b4d7ee89405ae5e4bc918578f60c02f18afe9a7e985001edf8af651cf4ac9a5b56a221cd39a6ace1aa9a8bd9e5c9e7ede1361884ff8661b41fc3ede7d9370edfdb3a334bf0d26d1af005fd25f174d89c025213f86eee1dcc6e81979763d34d136d492b89cd78272baba7c3879a632f296eb64ef5cf84d396dfdfb04b54247e7f41c66ce2f141154957b7c0fe3925664d82681e1a7a6e6c3843d3914910312b7d5b59fc344a0fcd6ae5845de17e1c0a47833c37092e0296d63902b00ef206a1125cf0d2924ad550cd3a03da8c154c24e26448f3c7d9f2bc9
I am not sure about the format of the param key of $rsa->verify. I tryed to add the prefix ssh-rsa. But it do not works better.
So I tryed the to signature format and the to key. The message is each time "unverified"

Thanks #neubert, it's du to PSS signature.
So here is the solution.
I use:
phpseclib : PHP lib used to validate message
jsrsasign : JS lib used to sign message
jsencrypt : JS lib to create private and public key
First, generate the keys in JS:
crypt = new JSEncrypt({default_key_size: 512});
var key = crypt.getKey();
var publicKey = key.getPublicKey();
var privateKey = key.getPrivateKey();
Secondly, create the signature:
var rsa = new RSAKey();
rsa.readPrivateKeyFromPEMString(privateKey);
var hSig = rsa.signStringPSS('message', 'sha1');
var signature = linebrk(hSig, 64);
console.log(signature);
By default the signature is not in the good format. We have to encode hSig in base 64 with the function base64Chars
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
b16to64 = function(h) {
var i;
var c;
var ret = "";
if(h.length % 2 == 1)
{
h = "0" + h;
}
for (i = 0; i + 3 <= h.length; i += 3)
{
c = parseInt(h.substring(i, i + 3), 16);
ret += base64Chars.charAt(c >> 6) + base64Chars.charAt(c & 63);
}
if (i + 1 == h.length)
{
c = parseInt(h.substring(i, i + 1), 16);
ret += base64Chars.charAt(c << 2);
}
else if (i + 2 == h.length)
{
c = parseInt(h.substring(i, i + 2), 16);
ret += base64Chars.charAt(c >> 2) + base64Chars.charAt((c & 3) << 4);
}
while ((ret.length & 3) > 0) ret += "=";
return ret;
}
To finish we validate in PHP. We assume the signature and the public key are stored in the vars with the same name:
$rsa = new Crypt_RSA();
$rsa->loadKey($publickey); // public key;
echo $rsa->verify('message', base64_decode($signature)) ? 'verified' : 'unverified';

Related

Convert xlsx (byte array) to csv(string) with javascript

I am from c# so know nothing about java script.
I have excel file (xlsx) that I red into byte array (with unity3d c# in webGL build) and want to send it into java script function that parse it into csv structure and return as string.
So the question part is only related to java script that received xlsx as byte array(or any type from memory stream) and return csv as string.
I need that function. What else (libs) do I need for that?
(Update)
The javascript code is
MyConverterXlsxToCsvReturn: function (array,size) {
var buffer = new ArrayBuffer(size);
for (var i = 0; i < size; i++)
buffer[i] = HEAPU8[array + i];
var txt = XLSX.utils.sheet_to_txt(buffer, {type: 'arraybuffer'});
window.alert(Pointer_stringify(txt));
window.alert(Pointer_stringify(txt.length));
var returnStr = Pointer_stringify(txt);
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
return buffer;
},
I am trying to send byte[] and convert into arraybuffer but in search of correct way to do that.
For now that function return empty string.
I wanted to convert byte array that I received in C# and then red the array in javascript.
As solution I converted the the byte array into hex string with method:
private string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
Then this string i sent to javascript function and converted to array. The rezult was returned as string:
ExcelHexToCSV: function (hexStr) {
console.log("javascript: ExcelHexToCSV");
console.log("javascript received: " + Pointer_stringify(hexStr));
// convert part
var str = Pointer_stringify(hexStr);
var a = [];
for (var i = 0, len = str.length; i < len; i += 2) {
a.push(parseInt(str.substr(i, 2), 16));
}
var data = new Uint8Array(a);
console.log("javascript hex_to_byte:" + data);
// excel part
var workbook = XLSX.read(data, {type: "array"});
var sheetname = workbook.SheetNames[0];
console.log("javascript sheetname: " + sheetname);
var sheetdata = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetname]);
console.log("javascript sheetdata: = " + sheetdata);
var rezult = sheetdata;
var returnStr = rezult;
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
return buffer;
},
Github link for the my example project

Java SHA-1 to javascript using CryptoJS

i have such a code to generate password written in Java
MessageDigest messageDigestPassword = MessageDigest.getInstance("SHA1");
messageDigestPassword .reset();
byte[] password = "password".getBytes();
messageDigestPassword .update(password);
byte[] encryptedPassword = messageDigestPassword .digest();
String date = "2019-10-22T11:33:13.393Z";
byte[] dateBytes = date.getBytes(StandardCharsets.UTF_8);
int offset = 0;
byte[] outputBytes = new byte[dateBytes.length + encryptedPassword .length];
System.arraycopy(dateBytes, 0, outputBytes, offset, dateBytes.length);
offset += dateBytes.length;
System.arraycopy(encryptedPassword , 0, outputBytes, offset, encryptedPassword .length);
MessageDigest finalMessageDigeset = MessageDigest.getInstance("SHA-1");
finalMessageDigeset.reset();
finalMessageDigeset.update(outputBytes);
byte[] finalPasswordBytes= finalMessageDigeset .digest();
String finalBase64Password = new String(Base64.encode(finalPasswordBytes));
and im trying to rewrite it to JavaScript to use it in postman with - CryptoJS
So far i have :
function wordArrayToByteArray(wordArray, length) {
if (wordArray.hasOwnProperty("sigBytes") &&
wordArray.hasOwnProperty("words")) {
length = wordArray.sigBytes;
wordArray = wordArray.words;
}
var result = [],
bytes,
i = 0;
while (length > 0) {
bytes = wordToByteArray(wordArray[i], Math.min(4, length));
length -= bytes.length;
result.push(bytes);
i++;
}
return [].concat.apply([], result);
}
function stringToBytes ( str ) {
var ch, st, re = [];
for (var i = 0; i < str.length; i++ ) {
ch = str.charCodeAt(i); // get char
st = []; // set up "stack"
do {
st.push( ch & 0xFF ); // push byte to stack
ch = ch >> 8; // shift value down by 1 byte
}
while ( ch );
// add stack contents to result
// done because chars have "wrong" endianness
re = re.concat( st.reverse() );
}
// return an array of bytes
return re;
}
var dateFixed = "2019-10-22T11:33:13.393Z";
var fixedDateBytes = stringToBytes(dateFixed);
var sha1Password= CryptoJS.SHA1("password");
console.log("sha1Password",sha1Password.toString(CryptoJS.enc.Hex));
var sha1PasswordBytes= wordArrayToByteArray(sha1Password, 20);
var concatedBytes= fixedDateBytes.concat(sha1PasswordBytes);
var finalShaPassWords= CryptoJS.SHA1(concatedBytes);
console.log("finalShaPassWords",finalShaPassWords.toString(CryptoJS.enc.Hex));
console.log("finalShaPassWords",finalShaPassWords.toString(CryptoJS.enc.Base64));
However unfortunatelly Base64 representations written in those 2 languages doesnt match.
I have checked and bytes from date are equal. Bytes from hashed password are not. So hashing after concat fails in JavaScript.
I have checked first password hashing and generated bytes and both of them are the same. So my guess line var sha1PasswordBytes= wordArrayToByteArray(sha1Password, 20); causes that line var finalShaPassWords= CryptoJS.SHA1(concatedBytes); returns bad value.
Can someone give me some idea what is wrong? Mayby it should be written diffrent ?
Since you are using CryptoJS anyway, you can also use the CryptoJS encoders and the WordArray#concat-method, which considerably simplifies the code:
var CryptoJS = require("crypto-js");
// Input
var inPwd = "password";
var inDate = "2019-10-22T11:33:13.393Z";
// Processing
var pwdHash = CryptoJS.SHA1(inPwd); // hash and convert to WordArray
var date = CryptoJS.enc.Utf8.parse(inDate); // convert to WordArray
var joinedData = date.clone().concat(pwdHash); // join date and hashed password
var joinedDataHash = CryptoJS.SHA1(joinedData); // hash joined data
var joinedDataHashB64 = CryptoJS.enc.Base64.stringify(joinedDataHash); // convert to Base64 string
// Output
console.log("Result: " + joinedDataHashB64 ); // Output: D235TBTZMfpSyB/CDl5MHAjH5fI=
The output of this code is the same as the output of the Java-code: D235TBTZMfpSyB/CDl5MHAjH5fI=

How to encode ??

During my research I've found these information but it seems like they are not really matching to my problem.
http://www.cplusplus.com/forum/beginner/31776/
Base 10 to base n conversions
https://cboard.cprogramming.com/cplusplus-programming/83808-base10-base-n-converter.html
So I'd like to implement a custom Base64 to BaseN encoding and decoding using C++.
I should be able to convert a (Base64)-string like "IloveC0mpil3rs" to a custom Base (e.g Base4) string like e.g "10230102010301" and back again.
Additional I should be able to use a custom charset (alphabet) for the base values like the default one probably is "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
So I should be able to use a shuffled one like e.g this (kind of encoding :) ): "J87opBEyWwDQdNAYujzshP3LOx1T0XK2e+ZrvFnticbCS64a9/Il5GmgVkqUfRMH".
I thought about translating the convertBase-function below from javascript into C++ but I'm obviously a beginner and got big problems, so I got stuck right there because my code is not working as expected and I can not find the error:
string encoded = convertBase("Test", 64, 4); // gets 313032130131000
cout << encoded << endl;
string decoded = convertBase(encoded, 4, 64); // error
cout << decoded << endl;
C++ code: (not working)
std::string convertBase(string value, int from_base, int to_base) {
string range = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/";
string from_range = range.substr(0, from_base),
to_range = range.substr(0, to_base);
int dec_value = 0;
int index = 0;
string reversed(value.rbegin(), value.rend());
for(std::string::iterator it = reversed.begin(); it != reversed.end(); ++it) {
index++;
char digit = *it;
if (!range.find(digit)) return "error";
dec_value += from_range.find(digit) * pow(from_base, index);
}
string new_value = "";
while (dec_value > 0) {
new_value = to_range[dec_value % to_base] + new_value;
dec_value = (dec_value - (dec_value % to_base)) / to_base;
}
return new_value;
}
javascript code: (working)
function convertBase(value, from_base, to_base) {
var range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
var from_range = range.slice(0, from_base);
var to_range = range.slice(0, to_base);
var dec_value = value.split('').reverse().reduce(function (carry, digit, index) {
if (from_range.indexOf(digit) === -1) throw new Error('Invalid digit `'+digit+'` for base '+from_base+'.');
return carry += from_range.indexOf(digit) * (Math.pow(from_base, index));
}, 0);
var new_value = '';
while (dec_value > 0) {
new_value = to_range[dec_value % to_base] + new_value;
dec_value = (dec_value - (dec_value % to_base)) / to_base;
}
return new_value || '0';
}
let encoded = convertBase("Test", 64, 4)
console.log(encoded);
let decoded = convertBase(encoded, 4, 64)
console.log(decoded);
Any help how to fix my code would be very appreciated!

Convert js function to python functions does't work

I have found an algorithm written in js (That I don't know how to code with) then I tried to convert it to python after a conversation with some friends who know js
Javascript
function crack(code) {
var N = '';
var M = '';
for(var i = 0; i < code.length; i++) {
if(i%2 == 0) {
N += code[i];
} else {
M = code[i] + M;
}
}
var key = N + M;
key = window.atob(key);
key = key.substring(2);
return key;
}
Python
import base64
def crack(code):
N = ''
M = ''
i = 0
for letter in code:
i =code.find(letter)
if i%2 == 0:
N += code[i]
else:
M =code[i] + M
key = N + M
key = base64.b64decode(key)
key = key[2:]
print key
As you can see it's the same code but the problem here that not give the same result !!
The string here to try on is:
N=m=NAobdtHRRHwaOuiU8mvcZhWddH5bZhz1MWzLapyR5nibbhG19ynccl3RBXvediCV5mjcbh2d0HubZhW1cWvLM4j8ACxONwi8
After searching for a while about window.atob found this method decodes a string of data which has been encoded by the btoa() method.
Then searched about btoa found this method uses the "A-Z", "a-z", "0-9", "+", "/" and "=" characters to encode the string.
Now what to do to get the same result with python ??
No. It's not the same code.
for(var i = 0; i < code.length; i++) {
if(i%2 == 0) {
is NOT the same as
for letter in code:
i =code.find(letter)
if i%2 == 0:
What happens if all letters in the code is the same?
I didn't look further than this.
I recommend doing a "literal" translation first, and THEN attempting a "Pythonic" modification to the code.
You are searching for the first occurrence of letter in the code, in the line i =code.find(letter). As you want the index, I recommend using enumerate
Result:
import base64
def crack(code):
N = ''
M = ''
i = 0
for i, letter in enumerate(code):
if i%2 == 0:
N += code[i]
else:
M =code[i] + M
key = N + M
key = base64.b64decode(key)
key = key[2:]
print key
Seems correct:
>>> crack('N=m=NAobdtHRRHwaOuiU8mvcZhWddH5bZhz1MWzLapyR5nibbhG19ynccl3RBXvediCV5mjcbh2d0HubZhW1cWvLM4j8ACxONwi8')
http://egyg33k.blogspot.com.eg/2016/08/8-malwarebytes-anti-malware.html

Generate public key from numbers

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 :)

Categories

Resources