I have two node-js programs. I want to sign a number data in the first program (node1.js) and verify that the in the second program (node2.js). But it is not happening. I think it may be because the way I'm sending the argument in write() is not correct. Please help. Thank You
node1.js
function between(min, max) {
return Math.floor(
Math.random() * (max - min) + min
)
}
var no = between(10, 100);
var crypto = require('crypto');
const node1PrivateKey = "-----BEGIN PRIVATE KEY-----\nMH4CAQAwEAYHKoZIzj0CAQYFK4EEAAMEZzBlAgEBBB4BfZ9QrDb9rRZB+sz5rkcK8VhUAJyJRj6KlOlEVYChQAM+AARylnQB587rYJlx/BvMIdtmLoMfzrCcYzrSMWxSX0tseCpunG03pBnE1mDuIo8lCnxm0kZYC4PUrr9r4f8=\n-----END PRIVATE KEY-----";
//var node1PublicKey = new Buffer("MFIwEAYHKoZIzj0CAQYFK4EEAAMDPgAEGrIPBS4+TSe1rKuuIcGItuYjAgVmIaILaa0MTIcTb7sth05hYtWKwfJA48ZTFQi5iBCH1RqCZyq+nZmB", "hex");
//keypair is correct and generated using other program
const sign = crypto.createSign('SHA256');
sign.write('no');
sign.end();
const signature = sign.sign(node1PrivateKey, 'hex');
module.exports = {
node1_no: no,
node1_signature: signature
}
node2.js
var crypto = require('crypto');
const node1PublicKey = "-----BEGIN PUBLIC KEY-----\nMFIwEAYHKoZIzj0CAQYFK4EEAAMDPgAEGrIPBS4+TSe1rKuuIcGItuYjAgVmIaILaa0MTIcTb7sth05hYtWKwfJA48ZTFQi5iBCH1RqCZyq+nZmB\n-----END PUBLIC KEY-----";
var node1 = require('./node1.js');
console.log(node1.node1_no);
console.log(node1.node1_signature);
const verify = crypto.createVerify('SHA256');
verify.write('node1.node1_no');
verify.end();
console.log(verify.verify(node1PublicKey, node1.node1_signature, 'hex'));
It returns FALSE.
The expected result is TRUE. when I use same variable name ('no') it returns TRUE.
Finally solved. The problem was write() function accepts only string. But I were sending integer value.
Now, I converted integer to string ans pass the value to write() function and it worked.
node1.js
function between(min, max) {
return Math.floor(
Math.random() * (max - min) + min
)
}
var no = between(10, 100);
var no_str = veh.toString();
var crypto = require('crypto');
const node1PrivateKey = "-----BEGIN PRIVATE KEY-----\nMH4CAQAwEAYHKoZIzj0CAQYFK4EEAAMEZzBlAgEBBB4BfZ9QrDb9rRZB+sz5rkcK8VhUAJyJRj6KlOlEVYChQAM+AARylnQB587rYJlx/BvMIdtmLoMfzrCcYzrSMWxSX0tseCpunG03pBnE1mDuIo8lCnxm0kZYC4PUrr9r4f8=\n-----END PRIVATE KEY-----";
//var node1PublicKey = new Buffer("MFIwEAYHKoZIzj0CAQYFK4EEAAMDPgAEGrIPBS4+TSe1rKuuIcGItuYjAgVmIaILaa0MTIcTb7sth05hYtWKwfJA48ZTFQi5iBCH1RqCZyq+nZmB", "hex");
const sign = crypto.createSign('SHA256');
sign.write('no_str');
sign.end();
const signature = sign.sign(node1PrivateKey, 'hex');
module.exports = {
node1_no: no,
node1_signature: signature
}
second.js
var crypto = require('crypto');
const node1PublicKey = "-----BEGIN PUBLIC KEY-----\nMFIwEAYHKoZIzj0CAQYFK4EEAAMDPgAEGrIPBS4+TSe1rKuuIcGItuYjAgVmIaILaa0MTIcTb7sth05hYtWKwfJA48ZTFQi5iBCH1RqCZyq+nZmB\n-----END PUBLIC KEY-----";
var node1 = require('./node1.js');
var no_string = node1.node1_veh
const verify = crypto.createVerify('SHA256');
verify.write('no_string');
verify.end();
console.log(verify.verify(node1PublicKey, node1.node1_signature, 'hex'));
Related
I'm triying to Encrypt string with C# and decrypt it using Angular crypto-js library but it's giving me different output.
I tried different c# aes encryption implementations but crypto-js library can't decrypt the encrypted data in c#. Thank you for any help.
Here is my code
Program.cs
static void Main()
{
var r = EncryptString("exampleString", "examplePassword");
Console.Write(r);
}
public static string EncryptString(string plainText, string passPhrase)
{
if (string.IsNullOrEmpty(plainText))
{
return "";
}
// generate salt
byte[] key, iv;
var salt = new byte[8];
var rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(salt);
DeriveKeyAndIv(passPhrase, salt, out key, out iv);
// encrypt bytes
var encryptedBytes = EncryptStringToBytesAes(plainText, key, iv);
// add salt as first 8 bytes
var encryptedBytesWithSalt = new byte[salt.Length + encryptedBytes.Length + 8];
Buffer.BlockCopy(Encoding.ASCII.GetBytes("Salted__"), 0, encryptedBytesWithSalt, 0, 8);
Buffer.BlockCopy(salt, 0, encryptedBytesWithSalt, 8, salt.Length);
Buffer.BlockCopy(encryptedBytes, 0, encryptedBytesWithSalt, salt.Length + 8, encryptedBytes.Length);
// base64 encode
return Convert.ToBase64String(encryptedBytesWithSalt);
}
private static void DeriveKeyAndIv(string passPhrase, byte[] salt, out byte[] key, out byte[] iv)
{
// generate key and iv
var concatenatedHashes = new List<byte>(48);
var password = Encoding.UTF8.GetBytes(passPhrase);
var currentHash = new byte[0];
var md5 = MD5.Create();
bool enoughBytesForKey = false;
// See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM
while (!enoughBytesForKey)
{
var preHashLength = currentHash.Length + password.Length + salt.Length;
var preHash = new byte[preHashLength];
Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
Buffer.BlockCopy(password, 0, preHash, currentHash.Length, password.Length);
Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + password.Length, salt.Length);
currentHash = md5.ComputeHash(preHash);
concatenatedHashes.AddRange(currentHash);
if (concatenatedHashes.Count >= 48)
enoughBytesForKey = true;
}
key = new byte[32];
iv = new byte[16];
concatenatedHashes.CopyTo(0, key, 0, 32);
concatenatedHashes.CopyTo(32, iv, 0, 16);
md5.Clear();
}
static byte[] EncryptStringToBytesAes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the stream used to encrypt to an in memory
// array of bytes.
MemoryStream msEncrypt;
// Declare the RijndaelManaged object
// used to encrypt the data.
RijndaelManaged aesAlg = null;
try
{
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
msEncrypt = new MemoryStream();
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Flush();
swEncrypt.Close();
}
}
}
finally
{
// Clear the RijndaelManaged object.
aesAlg?.Clear();
}
// Return the encrypted bytes from the memory stream.
return msEncrypt.ToArray();
}
Simply decrypting it using crypto-js
let CryptoJS = require('crypto-js');
let r = CryptoJS.AES.decrypt('exampleString', 'examplePassword').toString();
The example code is attempting to decrypt the original unencrypted string, which looks to be a mistake perhaps created when trying to simplify the example code for posting the question? Either way the steps required are not too difficult, but the toString() call needs to be replaced.
var data = "U2FsdGVkX1/Zvh/5BnLfUgfbg5ROSD7Aohumr9asPM8="; // Output from C#
let r2 = CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(data, 'examplePassword'));
console.log(r2);
I have this Python script which produces the correct output:
import hashlib
username = "LoginUser"
password = "LoginPass"
nonce = "1234567890"
def LowerCase(s): return s.lower()
def Hex(s): return ''.join([hex(char)[2:] for char in s])
def SHA1(s): h = hashlib.sha1(); h.update(s); return h.digest()
def SHA1Raw(s): h = hashlib.sha1(); h.update(s); return h.hexdigest()
def SHA256(s): h = hashlib.sha256(); h.update(s); return h.digest()
def SHA256Raw(s): h = hashlib.sha256(); h.update(s); return h.hexdigest()
def UTF8Encode(s): return str.encode(s)
step1 = SHA256((UTF8Encode(username)))
step2 = SHA1((UTF8Encode(password)))
step3 = SHA256Raw(step1 + step2)
step1 = SHA256Raw((UTF8Encode(username)))
step2 = SHA1Raw((UTF8Encode(password)))
print("""
SHA256(username={username}) = {step1}
SHA1(password={password}) = {step2}
SHA256((username + password)={username}{password}) = {step3}
""".format(
username = username,
password = password,
step1 = step1,
step2 = step2,
step3 = step3
))
Output:
PS D:\project> python .\test.py
SHA256(username=LoginUser) = 7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565
SHA1(password=LoginPass) = df703733447469593d39a125ca93462eade53cab
SHA256((username + password)=LoginUserLoginPass) = cf3066e157468d6a9d59f9ff0662e4f8f8432be4e07c68320a8b6a031d0c022b
Now in Javascript, I try to mirror the functions I have in Python. I cannot for the life of me. I tried quickly understanding Buffers and streams in this context but I believe I am just confusing myself further by not staying grounded to something.
Anyways here's the Javascript versiona and it's output:
const crypto = require('crypto')
const username = "LoginUser"
const password = "LoginPass"
const nonce = "1234567890"
const LowerCase = s => s.toLowerCase()
const Hex = s => Buffer.from(s, 'utf8').toString('hex')
const SHA1 = s => crypto.createHash('sha1').update(s, 'utf8').digest('hex')
const SHA1Raw = s => crypto.createHash('sha1').update(s, 'utf8').digest()
const SHA256 = s => crypto.createHash('sha256').update(s, 'utf8').digest('hex')
const SHA256Raw = s => crypto.createHash('sha256').update(s, 'utf8').digest()
const UTF8Encode = s => Buffer.from(s, 'utf8');
let step1 = SHA256(username)
let step2 = SHA1(password)
let step3 = SHA256Raw(step1.concat(step2))
console.log(`
SHA256(username=${username}) = ${step1}
SHA1(password=${password}) = ${step2}
SHA256((username + password)=${username+password}) = ${step3.toString('hex')}
`)
Output:
PS D:\project> node .\test.js
SHA256(username=LoginUser) = 7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565
SHA1(password=LoginPass) = df703733447469593d39a125ca93462eade53cab
SHA256((username + password)=LoginUserLoginPass) = 757101f0fd2628ce12dc039146f56da14a1e85a27fda5d68c2623f616c4fc3cc
Can anyone help?
You only need a very small modification to make this work in Node.js.
I would suggest calculating the hashes as buffer objects, this makes the combined hash easier to calculate (since we don't need to parse from hex).
We do this by using Buffer.concat to concatenate the output of the previous hashes.
const crypto = require('crypto')
const username = "LoginUser"
const password = "LoginPass"
const nonce = "1234567890"
const LowerCase = s => s.toLowerCase()
const Hex = s => Buffer.from(s, 'utf8').toString('hex')
const SHA1 = s => crypto.createHash('sha1').update(s, 'utf8').digest('hex')
const SHA1Raw = s => crypto.createHash('sha1').update(s, 'utf8').digest()
const SHA256 = s => crypto.createHash('sha256').update(s, 'utf8').digest('hex')
const SHA256Raw = s => crypto.createHash('sha256').update(s, 'utf8').digest()
const UTF8Encode = s => Buffer.from(s, 'utf8');
let step1 = SHA256Raw(username) // Get the SHA256 as a buffer.
let step2 = SHA1Raw(password) // Get the SHA1 as a buffer.
let step3 = SHA256Raw(Buffer.concat([step1, step2])) // Get the SHA256 of the previous steps concatenated as a buffer.
console.log(`
SHA256(username=${username}) = ${step1.toString('hex')}
SHA1(password=${password}) = ${step2.toString('hex')}
SHA256((username + password)=${username+password}) = ${step3.toString('hex')}
`)
This gives the correct result, e.g.
SHA256(username=LoginUser) = 7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565
SHA1(password=LoginPass) = df703733447469593d39a125ca93462eade53cab
SHA256((username + password)=LoginUserLoginPass) = cf3066e157468d6a9d59f9ff0662e4f8f8432be4e07c68320a8b6a031d0c022b
I am trying to reproduce the following C# decryption method in JavaScript.
This method is used to decrypt short strings: names, addresses, email addresses, etc.
It feels tantalisingly close, because the strings I have been able to "successfully" decrypt seem partially decrypted.
For instance, some of the emails look like this: x"R�Îd¹1gtWÈ2)web#example.com
CSharp
public static readonly byte[] INIT_VECTOR = { 0x00, 0x00, ... };
public static string Decrypt(string cipherText) {
string EncryptionKey = "Some Encryption Key";
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, INIT_VECTOR);
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
JavaScript
import atob from 'atob';
import forge from 'node-forge';
const InitVector = [0x00, ...];
const EncryptionKey = 'Some Encryption Key';
const iv = Buffer.from(InitVector).toString();
const convertBase64StringToUint8Array = input => {
const data = atob(input);
const array = Uint8Array.from(data, b => b.charCodeAt(0));
return array;
};
const decrypt = cipher => {
const cipherArray = convertBase64StringToUint8Array(cipher);
const key = forge.pkcs5.pbkdf2(EncryptionKey, iv, 1000, 32);
const decipher = forge.cipher.createDecipher('AES-CBC', key);
decipher.start({ iv });
decipher.update(forge.util.createBuffer(cipherArray, 'raw'));
const result = decipher.finish();
if (result) {
return decipher.output.data;
} else {
return false;
}
};
Thanks to kelalaka I managed to figure this out!
This was the code I ended up with.
import atob from 'atob';
import forge from 'node-forge';
const InitVector = [0x00, ...];
const EncryptionKey = 'Some Encryption Key';
const initKey = Buffer.from(InitVector).toString(); // Changed this to `initKey`
const convertBase64StringToUint8Array = input => {
const data = atob(input);
const array = Uint8Array.from(data, b => b.charCodeAt(0));
return array;
};
const decrypt = cipher => {
const cipherArray = convertBase64StringToUint8Array(cipher);
const key = forge.pkcs5.pbkdf2(EncryptionKey, iv, 1000, 32);
/**
* Added the following
* Note the key size = 48
* This was due to the fact that the C# dictated that
* the IV was 16 bytes, starting at the end of the key.
*/
const keyAndIV = forge.pkcs5.pbkdf2(encryptionKey, initKey, 1000, 32 + 16);
/**
* Therefore, we cut the iv from the new string
*/
const iv = keyAndIV.slice(32, 32 + 16); // 16 bytes
const decipher = forge.cipher.createDecipher(
'AES-CBC',
forge.util.createBuffer(key)
);
decipher.start({ iv });
decipher.update(forge.util.createBuffer(cipherArray, 'raw'));
const result = decipher.finish();
if (result) {
return decipher.output.data;
} else {
return false;
}
};
In order to write an simple nodejs app talking to an server written in java I have to implement the following functionality for nodejs.
public class Crypto {
Cipher decipher;
byte[] salt = {
(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
(byte) 0x0A, (byte) 0x0B, (byte) 0x0C, (byte) 0x0D
};
int iterationCount = 10;
public Crypto(String pass) {
try {
KeySpec keySpec = new PBEKeySpec(pass.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance(
"PBEWithMD5AndTripleDES").generateSecret(keySpec);
ecipher = Cipher.getInstance("PBEWithMD5AndTripleDES/CBC/PKCS5Padding");
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
decipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception ex) {
}
}
}
I use the crypto module of nodejs
var crypto = require('crypto'),
pass = new Buffer(wek),
salt = new Buffer([0x01, 0x02, 0x03, 0x04, 0x0A, 0x0B, 0x0C, 0x0D])
password = 'mySecretPassword'
key = crypto.pbkdf2(pass, salt, 10, 256)
cipher,
encrypted;
cipher = crypto.createCipher('des-ede-cbc', key);
encrypted = cipher.update(new Buffer('the very secred information'));
After sending the encrypted information to the server, I can't decrypt the message with the decipher Object as listed in the java code sample above. I think the main problem is the md5 part. I can't figure out how to implement that with the crypto nodejs module. Has anyone an idea how to solve this problem? Or is ther any other module or library to achieve that?
EDIT: I tried another module for nodejs: node-forge
forge = require('node-forge')
var numIterations = 10,
keyLength = 24,
password = forge.util.createBuffer('mySecretPassword'),
salt = new forge.util.ByteBuffer(new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x0A, 0x0B, 0x0C, 0x0D])),
derivedKey = forge.pkcs5.pbkdf2(password, salt.getBytes(), numIterations, keyLength, forge.md.md5.create())
iv = {}; // TODO... ???
var cipher = forge.des.createEncryptionCipher(derivedKey);
cipher.start(iv);
cipher.update('the very secred information');
cipher.finish();
var encrypted = cipher.output;
But I have several problems/questions:
Do I use the correct algorithm in javascript?
Is the salt calculation match with the java implementation?
How can I determine which keyLength is used in the java implementation?
How is the initialization vector generated in the java implementation? In the last code sample with node-forgeI have to provide the iv on cipher.start(iv). In the java code I can't see how this is done. In my opinion the iv must be the same on client and server or is this incorrect?
I reverse engineered the DESede part of the key derivation function found at com.sun.crypto.provider.PBES1Core#deriveCipherKey();
We use Jasypt as encryption library in a Java server and our node.js server is able to encrypt and decrypt with this. I hope it helps (Written in ES2015, runs in node v4.0.0 and up):
'use strict';
var crypto = require('crypto');
class Encryption {
constructor() {
this.privateKey = new Buffer('<your password>', 'utf-8');
}
encrypt(message) {
var salt = crypto.randomBytes(8);
var key = this._generateKey(this.privateKey, salt);
var cipher = crypto.createCipheriv('des-ede3-cbc', this._subBuf(key, 0, 24), this._subBuf(key, 24));
var result = cipher.update(message, 'utf-8', 'hex');
return salt.toString('hex') + result + cipher.final('hex');
}
decrypt(message) {
var salt = new Buffer(message.substr(0, 16), 'hex');
var key = this._generateKey(this.privateKey, salt);
message = message.substr(16);
var decipher = crypto.createDecipheriv('des-ede3-cbc', this._subBuf(key, 0, 24), this._subBuf(key, 24));
var result = decipher.update(message, 'hex', 'utf-8');
return result + decipher.final('utf-8');
}
_generateKey(password, salt) {
if (!(password instanceof Buffer)) {
throw new Error('Password needs to be a buffer');
}
if (!(salt instanceof Buffer) || salt.length != 8) {
throw new Error('Salt needs to be an 8 byte buffer');
}
var iterations;
for(iterations = 0; iterations < 4 && salt[iterations] == salt[iterations + 4]; ++iterations) {}
if(iterations == 4) {
for(iterations = 0; iterations < 2; ++iterations) {
var tmp = salt[iterations];
salt[iterations] = salt[3 - iterations];
salt[2] = tmp; // Seems like an error that we have to live with now
}
}
var result = new Buffer(32);
for(iterations = 0; iterations < 2; ++iterations) {
var intermediate = new Buffer(salt.length / 2);
for (let i = 0; i < salt.length / 2; i++) {
intermediate[i] = salt[iterations * (salt.length / 2) + i];
}
for(let i = 0; i < 1000; ++i) {
var hash = crypto.createHash('md5');
hash.update(intermediate);
hash.update(password);
intermediate = hash.digest();
}
for (let i = 0; i<intermediate.length; i++) {
result[i + (iterations * 16)] = intermediate[i];
}
}
return result;
}
_subBuf(buffer, start, length) {
if (!length) {
length = buffer.length - start;
}
var result = new Buffer(length, 'hex');
for (let i = 0; i < length; i++) {
result[i] = buffer[i + start]
}
return result;
}
}
To explain a little what's going on:
Encrypted messages are returned in hex format, something else might fit your implementation better.
The _generateKey() is a direct copy from the java source.
The keys used are 32 byte length and assume that the first 24 bytes are the keys for TripleDES and the last 8 are the salt
The generated message is prefixed with the random generated salt that used to encrypt the message.
Depending on the security settings of your JVM it might be possible that you are not actually using des-ede3 (cbc seems to be a fixed setting). You should definitely double check if this works with your setup.
Some code clean up might be necessary here, but it should at least get you started in the right direction.
My final solution 5 years ago was:
var forge = require('node-forge');
var crypto = require('crypto');
var base64Coder = require('./utils/tac-base64coder');
var ByteBuffer = forge.util.ByteBuffer;
var DES_EDE_KEY_LEN = 24;
var DES_BLOCK_SIZE = 8;
var SALT_BYTES = [0x45, 0xC4, 0x31, 0x72, 0x8A, 0x62, 0xB3, 0x9A];
var KEY_BUFFER_LENGTH = 24;
var IV_BUFFER_LENGTH = 8;
module.exports = {
/**
* Generates the derived key. The 16 bytes of the first digest and the 1st 8 bytes of the 2nd digest
* form the triple DES key, and the last 8 bytes of the 2nd digest form the IV.
*
* #method _deriveCipherKey
* #param {String} key The key phrase
* #param {Int8Array} salt The salt
* #param {Number} iCount The iteration count
* #returns {Buffer}
* #private
*/
_deriveCipherKey: function _deriveCipherKey (key, salt, iCount) {
var md;
var passwdBytes = new Buffer(key);
var i;
var toBeHashed;
var result = new Buffer(DES_EDE_KEY_LEN + DES_BLOCK_SIZE);
result.fill(0);
// if the 2 salt halves are the same, invert one of them
for (i = 0; i < 4; i++) {
if (salt[i] !== salt[i + 4]) {
break;
}
}
if (i === 4) { // same, invert 1st half
for (i = 0; i < 2; i++) {
var tmp = salt[i];
salt[i] = salt[3 - i];
salt[3 - 1] = tmp;
}
}
for (i = 0; i < 2; i++) {
toBeHashed = new Buffer(salt.length / 2);
toBeHashed.fill(0);
salt.copy(toBeHashed, 0, i * (salt.length / 2));
for (var j = 0; j < iCount; j++) {
md = crypto.createHash('md5');
md.update(toBeHashed);
md.update(passwdBytes);
toBeHashed = md.digest();
}
toBeHashed.copy(result, i * 16);
}
return result;
},
/**
* Encrypts the given string with the given key
*
* #method encrypt
* #param {String} encryptionKey The encryption key
* #param {String} toEncrypt The string to encrypt
* #returns {String}
*/
encrypt: function encrypt (encryptionKey, toEncrypt) {
var encodedStr = forge.util.encodeUtf8(toEncrypt);
var salt = new Buffer(SALT_BYTES);
var key = new Buffer(KEY_BUFFER_LENGTH);
var iv = new Buffer(IV_BUFFER_LENGTH);
var key2 = new ByteBuffer();
var iv2 = new ByteBuffer();
var derivedKey = this._deriveCipherKey(encryptionKey, salt, 12);
var cipher;
var i = 0;
derivedKey.copy(key, 0, 0, 24);
derivedKey.copy(iv, 0, 24);
for (; i < KEY_BUFFER_LENGTH; i++) {
key2.putByte(key[i]);
}
for (i = 0; i < IV_BUFFER_LENGTH; i++) {
iv2.putByte(iv[i]);
}
cipher = forge.des.createEncryptionCipher(key2);
cipher.start(iv2);
cipher.update(forge.util.createBuffer(encodedStr));
cipher.finish();
return base64Coder.encode(cipher.output.getBytes().toString());
},
/**
* Decrypts the given base64 string with the given key
*
* #method decrypt
* #param {String} encryptionKey The decryption key
* #param {String} toDecrypt The encrypted base64 string
* #returns {String}
*/
decrypt: function decrypt (encryptionKey, toDecrypt) {
var decr = forge.util.decode64(toDecrypt);
var salt = new Buffer(SALT_BYTES);
var key = new Buffer(KEY_BUFFER_LENGTH);
var iv = new Buffer(IV_BUFFER_LENGTH);
var derivedKey = this._deriveCipherKey(encryptionKey, salt, 12);
var key2 = new forge.util.ByteBuffer();
var iv2 = new forge.util.ByteBuffer();
var i = 0;
var cipher;
derivedKey.copy(key, 0, 0, 24);
derivedKey.copy(iv, 0, 24);
for (; i < KEY_BUFFER_LENGTH; i++) {
key2.putByte(key[i]);
}
for (i = 0; i < IV_BUFFER_LENGTH; i++) {
iv2.putByte(iv[i]);
}
cipher = forge.des.createDecryptionCipher(key2);
cipher.start(iv2);
cipher.update(forge.util.createBuffer(decr));
cipher.finish();
return cipher.output.getBytes().toString('utf8');
}
};
i have this pseudo code and i would like to convert it into working code:
string constructSignature(string timestamp, string UID, string secretKey) {
baseString = timestamp + "_" + UID; // Construct a "base string" for signing
binaryBaseString = ConvertUTF8ToBytes(baseString); // Convert the base string into a binary array
binaryKey = ConvertFromBase64ToBytes(secretKey); // Convert secretKey from BASE64 to a binary array
binarySignature = hmacsha1(binaryKey, baseString); // Use the HMAC-SHA1 algorithm to calculate the signature
signature = ConvertToBase64(binarySignature); // Convert the signature to a BASE64
return signature;
}
any idea?
thanks
Some ideas:
Don't calculate BinaryBaseString, given that you never use it
Don't refer to UTF8 for no reason at all -- strings in JavaScript are Unicode, which is only distantly connected to UTF.
Don't put implementation details in your pseudocode -- especially ones you don't actually need (like assuming the secret key should be in "bytes", whatever that means, when in fact, the standard library takes and returns strings).
Don't write comments that just restate what the code is doing.
Which leaves us with:
var constructSignature = function(timestamp, UID, secretKey) {
return Crypto.HMAC(Crypto.SHA1, timestamp + "_" + UID, secretKey,
{ asString: true });
};
Here is a full implementation of your code:
let atob = function(a){
return new Buffer(a, 'base64').toString('binary');
}
function ConvertUTF8ToBytes(str) {
var utf8 = unescape(encodeURIComponent(str));
var arr = [];
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i));
}
return new Uint8Array(arr);
}
let ConvertFromBase64ToBytes = function (b64Data){
var byteCharacters = atob(b64Data);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
return new Uint8Array(byteNumbers);
}
let constructSignature = function(timestamp, UID, secretKey) {
let baseString = timestamp + "_" + UID;
let binaryBaseString = ConvertUTF8ToBytes(baseString)
let binaryKey = ConvertFromBase64ToBytes(secretKey)
let binarySignature = Crypto.createHmac('sha1', binaryKey)
.update( binaryBaseString )
.digest('base64');
return binarySignature;
};