how to convert this code in javascript to java - javascript

i have this code in javascript and i need to convert it to java
but im not expert in javascript.
here the code:
function keyGen(mat)
{
var hash = base64_encode(pack("H*", sha1($mat)));
var l = obj.hash.length - 4;
var p1 = Math.floor(Math.random() * (l+1)) ;
var p2 = Math.floor(Math.random() * (l+1)) ;
var p3 = Math.floor(Math.random() * (l+1)) ;
var motif1 = obj.hash.substr(p1, 4) ;
var motif2 = obj.hash.substr(p2, 4) ;
var motif3 = obj.hash.substr(p3, 4) ;
var cle = motif1+motif2+motif3 ;
return cle ;
}
for the hash i use the function but i can't to modify it:
public static String get_SHA_512_SecurePassword(String passwordToHash, String salt){
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(salt.getBytes(StandardCharsets.UTF_8));
byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++){
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e){
e.printStackTrace();
}
return generatedPassword;
}

function keyGen(mat) {
// seems to get the sha1 of $mat (whatever that is),
// converts this sha1 into HEX string
// encode the hex string into into base64
// the above is a GUESS, as I don't know what library you are using for these functions
var hash = base64_encode(pack("H*", sha1($mat)));
// length of `obj.hash` - whatever that is
var l = obj.hash.length - 4;
// random number between 0 and l + 1
var p1 = Math.floor(Math.random() * (l+1)) ;
// random number between 0 and l + 1
var p2 = Math.floor(Math.random() * (l+1)) ;
// random number between 0 and l + 1
var p3 = Math.floor(Math.random() * (l+1)) ;
// a substring of whatever obj.hash is, from position p1 length 4
var motif1 = obj.hash.substr(p1, 4) ;
// a substring of whatever obj.hash is, from position p2 length 4
var motif2 = obj.hash.substr(p2, 4) ;
// a substring of whatever obj.hash is, from position p3 length 4
var motif3 = obj.hash.substr(p3, 4) ;
// the string concatenation of the above three strings
var cle = motif1+motif2+motif3 ;
// returns this 12 character string
return cle ;
}
Now, all you need to figure out is
What is base64_encode
what is pack
what is sha1
what is $mat
what is obj that you use obj.hash from
why you are creating hash and never using it
why you never use the mat argument

here is the full code : i found it ..... thanks all
public static String get_SHA_512_SecurePassword(String passwordToHash, String salt){
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(salt.getBytes(StandardCharsets.UTF_8));
byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++){
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
// String base64 = Base64.encodeBase64(sb.toString());
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e){
e.printStackTrace();
}
return generatedPassword;
}
public static String keyGen(String Studentpass,String SaltCrypter) {
String hash=get_SHA_512_SecurePassword(Studentpass,SaltCrypter);
int l = hash.length() - 4;
new Random().nextInt();
int p1 = new Random().nextInt(l) ;
int p2 = new Random().nextInt(l) ;
int p3 = new Random().nextInt(l) ;
String motif1 = hash.substring(p1, p1+4);
String motif2 = hash.substring(p2, p2+4);
String motif3 = hash.substring(p3, p3+4);
String cle =(motif1+motif2+motif3);
cle.replace("l", "L").replace("O", "o").replace("I", "i");
return cle;
}

let arr = [
{url: 'http://172.25.38.138:4000/moservice/create1', startTime: '04/11/2022 16:04:15', endTime: '04/11/2022 16:24:15'},
{url: 'http://172.25.38.138:4000/moservice/create2', startTime: '04/11/2022 16:24:15', endTime: '04/11/2022 16:34:15'},
{url: 'http://172.25.38.138:4000/moservice/create3', startTime: '04/11/2022 16:34:15', endTime: '04/11/2022 16:54:15'},
{url: 'http://172.25.38.138:4000/moservice/create4', startTime: '04/11/2022 17:04:15', endTime: '04/11/2022 17:14:15'}
];
let curntTime = new Date()
function getUrl(arr) {
for (let i = 0; i < arr.length; i++) {
let startTime = new Date(arr[i].startTime)
let endTime = new Date(arr[i].endTime)
if (curntTime > startTime && curntTime < endTime) {
console.log(arr[i].url)
}
}
}
getUrl(arr)
B

Related

How to decrypt large files (1 GB) with AES-CTR chunk by chunk in javascript (browsers)?

We are trying to decrypt large files (1GB) in browsers. With AES-CTR it should be possible to decrypt chunk by chunk - where chunk must be the correct size and you also have to provide nonce + counter.
Does anyone have any examples or ideas how to do this in javascript?
What we tried so far:
var length = value.byteLength;
var chunkSize = 128;
var index = 0;
let chunks = [];
let aesCounter = byteArrayToLong(subtleIv);
do {
let newCount = aesCounter + index / 16;
var decrypted = await window.crypto.subtle.decrypt({name: "AES-CTR", counter: Buffer.from(longToByteArray(newCount)), length: chunkSize}, subtleKey, value.slice(index, index+chunkSize));
chunks.push(Buffer.from(decrypted));
index += chunkSize;
} while(index < length);
let newCount = aesCounter + index / 16;
decrypted = await window.crypto.subtle.decrypt({name: "AES-CTR", counter: Buffer.from(longToByteArray(newCount)), length: chunkSize}, subtleKey, value.slice(index, index+chunkSize));
chunks.push(Buffer.from(decrypted));
let decryptedAll = Buffer.concat(chunks);
function longToByteArray(/*long*/long) {
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for ( var index = 0; index < byteArray.length; index ++ ) {
var byte = long & 0xff;
byteArray [ index ] = byte;
long = (long - byte) / 256 ;
}
return byteArray;
}
function byteArrayToLong(/*byte[]*/byteArray) {
var value = 0;
for ( var i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
}
return value;
}
The only flaw in your implementation is actually the conversion between integer and byte array. Firstly, in JavaScript the maximum integer is 0x1FFFFFFFFFFFFF, see here, secondly, even with smaller numbers the little endian order is used, but the WebCrypto API applies the big endian order.
As a first step to a fix you could use e.g. the BigInt implementation of JavaScript and the here described conversion between BigInt and ArrayBuffer.
Since this implementation works with ArrayBuffer and Uint8Array respectively, an implementation for concatenation is needed, e.g. from here.
This changes your implementation slightly as follows (key, IV and ciphertext are imported hex encoded):
(async () => {
// Key import
var keyHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
var key = hex2ab(keyHex);
var subtleKey = await window.crypto.subtle.importKey(
"raw",
key,
{ name: "AES-CTR" },
false,
["encrypt", "decrypt"]
);
// IV import
var ivHex = "404142434445464748494a4b4c4d4e4f";
var subtleIv = hex2ab(ivHex);
// Ciphertext import
var ciphertextHex = "ef11ad5afa7ad39fe00e0fe7e934dd38c2556dfadcce052cee9d91ee33393b428013d78ed995d5248cadd7be2d855e1adc932167d779923170447505c164eb46b59efd59e695de56512366738072afee57c16a71583346e0eac4a52dbb423b86e1c931ed7bdc3bbc17e5c662ad9cf676a7053ed435eb0968e6b1108531e2f686f491a8e2c02e43edda8162407b9e774f517e8cc8c683bada7044b1573d501a2ac54022ca1e98e26fa0f6ab60485124adb76472af0a5780a0fc2c3332cceed5395339aef3c818996bd24dd5a8d3573eab4646de859b318810dee23fb4558be8932ab790bd87d5f66531943a8bf7c70ea21b44aca6285e1e48a5852fcfa2beda61cd9f0745b8e6c10161678743b307e4ccfcb49e4c44216c32dd7e65a9f408e0aca457a9a92223e14d5d48c7855db0f7cf97e1dd176391beb0c4ecc466c9a6c4cdb211540cfd0448f4cc35b9719f31c9caf440d2aab66a42f92c65993b216449cef809ca65152bd0b509de4a7f859d630e4a5cb5c17eb6815ed1291379fe547801c7ab22501d2da6fd73111697d275b4086b455e66a36e9e8ad62f1910a832e9461606d88c407e6969f2044ff34417d391d0f6c97480264fd3c7e1b45acc";
var ciphertext = hex2ab(ciphertextHex);
// Decrypt and concat
var length = ciphertext.byteLength;
var chunkSize = 128; // chunkSize in bytes
var index = 0;
var chunks = [];
var aesCounter = bufToBn(subtleIv);
do {
var newCount = aesCounter + BigInt(index / 16); // index / 16 = number of blocks
var decrypted = await window.crypto.subtle.decrypt({name: "AES-CTR", counter: bnToBuf(newCount), length: 128}, subtleKey, ciphertext.slice(index, index+chunkSize)); // length in bits
chunks.push(new Uint8Array(decrypted));
index += chunkSize;
} while(index < length);
var mergedChunks = merge(chunks);
// Decode and output
var decrypted = String.fromCharCode.apply(null, mergedChunks);
console.log(decrypted);
// https://coolaj86.com/articles/convert-js-bigints-to-typedarrays/
function bnToBuf(bn) {
var hex = BigInt(bn).toString(16);
if (hex.length % 2) { hex = '0' + hex; }
var len = hex.length / 2;
var u8 = new Uint8Array(len);
var i = 0;
var j = 0;
while (i < len) {
u8[i] = parseInt(hex.slice(j, j+2), 16);
i += 1;
j += 2;
}
return u8;
}
function bufToBn(buf) {
var hex = [];
u8 = Uint8Array.from(buf);
u8.forEach(function (i) {
var h = i.toString(16);
if (h.length % 2) { h = '0' + h; }
hex.push(h);
});
return BigInt('0x' + hex.join(''));
}
// https://stackoverflow.com/a/49129872/9014097
function merge(chunks){
let size = 0;
chunks.forEach(item => {
size += item.length;
});
let mergedArray = new Uint8Array(size);
let offset = 0;
chunks.forEach(item => {
mergedArray.set(item, offset);
offset += item.length;
});
return mergedArray;
}
function hex2ab(hex){
return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)}));
}
})();
which successfully decrypts the ciphertext. Btw, the ciphertext was generated with CyberChef.
Unlike the WebCrypto API, CryptoJS supports progressive encryption, so the same logic can be implemented significantly easier with CryptoJS:
// Key import
var keyHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
var keyWA = CryptoJS.enc.Hex.parse(keyHex);
// IV import
var ivHex = "404142434445464748494a4b4c4d4e4f";
var ivWA = CryptoJS.enc.Hex.parse(ivHex);
// Ciphertext import
var ciphertextHex = "ef11ad5afa7ad39fe00e0fe7e934dd38c2556dfadcce052cee9d91ee33393b428013d78ed995d5248cadd7be2d855e1adc932167d779923170447505c164eb46b59efd59e695de56512366738072afee57c16a71583346e0eac4a52dbb423b86e1c931ed7bdc3bbc17e5c662ad9cf676a7053ed435eb0968e6b1108531e2f686f491a8e2c02e43edda8162407b9e774f517e8cc8c683bada7044b1573d501a2ac54022ca1e98e26fa0f6ab60485124adb76472af0a5780a0fc2c3332cceed5395339aef3c818996bd24dd5a8d3573eab4646de859b318810dee23fb4558be8932ab790bd87d5f66531943a8bf7c70ea21b44aca6285e1e48a5852fcfa2beda61cd9f0745b8e6c10161678743b307e4ccfcb49e4c44216c32dd7e65a9f408e0aca457a9a92223e14d5d48c7855db0f7cf97e1dd176391beb0c4ecc466c9a6c4cdb211540cfd0448f4cc35b9719f31c9caf440d2aab66a42f92c65993b216449cef809ca65152bd0b509de4a7f859d630e4a5cb5c17eb6815ed1291379fe547801c7ab22501d2da6fd73111697d275b4086b455e66a36e9e8ad62f1910a832e9461606d88c407e6969f2044ff34417d391d0f6c97480264fd3c7e1b45acc";
var ciphertextWA = CryptoJS.enc.Hex.parse(ciphertextHex);
// Decrypt and concat
var length = ciphertextWA.sigBytes;
var chunkSize = 128;
var index = 0;
var decryptedWA = CryptoJS.enc.Hex.parse("");
var aesDecryptor = CryptoJS.algo.AES.createDecryptor(keyWA, { iv: ivWA, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
var chunk = null;
do {
chunk = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(index/4, (index + chunkSize)/4));
decryptedWA = decryptedWA.concat(aesDecryptor.process(chunk));
index += chunkSize;
} while(index < length - chunkSize);
chunk = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(index/4, (index + chunkSize)/4));
chunk.sigBytes = length - index;
chunk.clamp();
decryptedWA = decryptedWA.concat(aesDecryptor.process(chunk));
decryptedWA = decryptedWA.concat(aesDecryptor.finalize());
// Decode and output
var decrypted = decryptedWA.toString(CryptoJS.enc.Utf8);
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
A drawback of the first variant is that the BigInt class should actually not be used in the context of cryptography, since the operations are not constant-time, which results in a vulnerability to timing attacks. So, here you would have to apply a cryptographically more secure JavaScript BigInteger implementation for production.
For such reasons, the use of an established library (as opposed to a custom implementation), such as CryptoJS, is generally more secure (although ultimately vulnerabilities cannot be ruled out here either).
You are well on your way; cutting the ciphertext in chunks of C-blocks and then updating the counter block according to the block count is exactly what you should be doing.
However, note that the counter block is 128 bits: the longToByteArray should be called createCounterBlock(nonce, counter). The nonce should be contained in the initial/leftmost (8?) bytes. The counter is encoded as unsigned big endian in the final/rightmost 8 bytes, making 16 bytes total. This you can then provide as an IV to decrypt the chunk.
Currently your counter is placed in the leftmost bytes, which will fail for most CTR implementations; I don't think that JS uses 128 bit integers. Officially the contents of the counter block is not defined, but generally a big endian 128 bit value is used.

How to implement java MessageDigest with CryptoJS

JAVA CODE:
byte[] n;
byte[] m;
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
digest.update(n);
byte[] hashed = digest.digest(m);
StringBuilder hexValue = new StringBuilder();
for (byte b : hashed) {
int val = ((int) b) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
System.out.println(hexValue.toString());
How to implement the above code with CryptoJS ?
Thanks!
The following codeļ¼š
var n; // n="abc"
var m; // m="123"
var sha1 = CryptoJS.algo.SHA1.create();
sha1.update(n);
var hashed = sha1.finalize(m);
console.log(hashed.toString());

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=

JavaScript To Java Exception in thread "main" java.lang.NumberFormatException: For input string: ""

Hi am trying to convert my JavaScript decrypt method to Java can't seem to be able to do it since am stuck here i am inputting the string i don't why its saying am not ...
Error Code:
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:592)
at ae.df.sux.Main.Decrypt1(Main.java:42)
at ae.df.sux.Main.main(Main.java:7)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Java Code:
public static String Decrypt1(String strIn) {
String strOut = "";
int lenIn = strIn.length();
int i = 0;
int A;
int B;
while (i < lenIn) {
A = Integer.parseInt(strIn.substring(i, 2), 27);
B = Integer.parseInt(strIn.substring(i + 2, 2), 27);
strOut+= fromCharCode(A - B);
i+=4;
}
return strOut;
}
JavaScript:
Decrypt1 = function (strIn) {
var strOut = String();
var lenIn = strIn.length;
var i = 0;
var numA;
var numB;
while (i < lenIn) {
numA = parseInt(strIn.substr(i, 2), 27);
numB = parseInt(strIn.substr(i + 2, 2), 27);
strOut += String.fromCharCode(numA - numB);
i += 4;
}
return strOut;
};
The java error line:
B = Integer.parseInt(strIn.substring(i + 2, 2), 27);
So the value is encrypted:
431o5m215e1e723d7o3h6f2j401j4j2d7b345k1c631o59267j3g6627531a7a385o3g5125582g592n4l1l66395d2d4b1l4i1p531m4a1f5k2g4p2e4o205h2j693j3l1f593g7d3679317832511p5i1f6l2m6i2p7f3d58305f397g3j5c1a712k4e21783c5m267d374g1o5p3b4b234p314h2l4q2n52325e3i391b44215a3d5a344q36793c74325i1a411f6h2l5i226o2i4o254e205k3c552q391g682e7b3b5h216l2e6k2o3j1b
It should return:
<flash><strToken>MICQNQGJYLUANOG</strToken><intCharID>32962493</intCharID></flash>
I don't know what the problem is thanks for the help.
Not all Java functions behave exactly as same as other javascript functions. You have to check what the function returns. I have modified your java code to get desired output.
public static String Decrypt1(String strIn) {
String strOut = "";
int lenIn = strIn.length();
int i = 0;
int A;
int B;
int nextIndex = 0;
while (i < lenIn) {
nextIndex = i+4;
String aStr= strIn.substring(i, i+2);
String bStr= strIn.substring(i + 2, nextIndex);
System.out.println("astr:"+aStr);
System.out.println("bstr:"+bStr);
A = Integer.parseInt(aStr, 27);
B = Integer.parseInt(bStr, 27);
System.out.println("A:"+A);
System.out.println("B:"+B);
int C = A- B;
System.out.println("C:"+C);
String charStr = new String(Character.toChars(C));
System.out.println("charStr :" +charStr);
strOut+= charStr;
i+=4;
}
System.out.println("output:"+strOut);
return strOut;
}
output:<flash><strToken>MICQNQGJYLUANOG</strToken><intCharID>32962493</intCharID></flash>

Nodejs javascript implementation of PBEWithMD5AndTripleDES/CBC/PKCS5Padding

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');
}
};

Categories

Resources