TripleDES .Net to TripleDES (crypto-js) Javascript - cryptojs

I've spent some time looking at all solutions but something still seems off.. The encrypted string I see in .Net does not match the output I see in Cryto-JS. What could be wrong?
public static void Encrypt()
{
string toEncrypt = "123456";
string key = "hello";
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
byte[] keyArray = hashmd5.ComputeHash(UnicodeEncoding.Unicode.GetBytes(key));
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] toEncryptArray = UnicodeEncoding.Unicode.GetBytes(toEncrypt);
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
string finalString = Convert.ToBase64String(resultArray);
Console.WriteLine("Output encrypted .Net: " + finalString);
}
and the equivalent Javascript using crypto-js is
Encrypt = () => {
var CryptoJS = require('crypto-js');
var text = '123456'
var key = "hello";
key = CryptoJS.enc.Utf16LE.parse(key);
key = CryptoJS.MD5(key)
var options = {
mode: CryptoJS.mode.ECB,
};
var textWordArray = CryptoJS.enc.Utf16LE.parse(text);
var encrypted = CryptoJS.TripleDES.encrypt(textWordArray, key, options);
var base64String = encrypted.toString();
console.log('Output JS Encrypted: ' + base64String);
}
I get yGOnLhoVpIHQOCbAn51FTA== in .Net and d5Lg8k8cz68T6akDI0KQrA== in crypto-js.

I have fixed this issue. A console log inside tripledes.js (CryptoJS package) revealed that I was missing 64 more bits in the key after MD5 Hash.
this._des1 = DES.createEncryptor(WordArray.create(keyWords.slice(0, 2)));
this._des2 = DES.createEncryptor(WordArray.create(keyWords.slice(2, 4)));
this._des3 = DES.createEncryptor(WordArray.create(keyWords.slice(4, 6)));
key.words length was 4 instead of 6. So, des3 had an empty wordarray. Solution was to push value of index 0 and 1 into the key word array. With length now being 6, des3 gets the value of des1. i.e keyWords.slice(0, 2) = keyWords.slice(4, 6).
Encrypt = () => {
var CryptoJS = require('crypto-js');
var text = '123456'
var key = "hello";
key = CryptoJS.enc.Utf16LE.parse(key);
key = CryptoJS.MD5(key)
key.words.push(key.words[0], key.words[1]) // FIX FIX FIX
var options = {
mode: CryptoJS.mode.ECB,
};
var textWordArray = CryptoJS.enc.Utf16LE.parse(text);
var encrypted = CryptoJS.TripleDES.encrypt(textWordArray, key, options);
var base64String = encrypted.toString();
console.log('Output JS Encrypted: ' + base64String);
}

Related

Can't replicate simple hashing signature example from Amazon

I'm trying to create the final step of this example in Flutter and I can't get it right for some reason:
https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
Using their Signing Key + String to sign they get this resulting signature:
5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
Using the exact same key / string to sign I end up with:
fe52b221b5173b501c9863cec59554224072ca34c1c827ec5fb8a257f97637b1
Here is my code:
var testSigninKey =
'c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9';
var testStringToSign = 'AWS4-HMAC-SHA256' + '\n' +
'20150830T123600Z' + '\n' +
'20150830/us-east-1/iam/aws4_request' + '\n' +
'f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59';
var hmac1 = Hmac(sha256, utf8.encode(testSigninKey));
var digest1 = hmac1.convert(utf8.encode(testStringToSign));
print(digest1);
print(hex.encode(digestBytes.bytes));
//both print: fe52b221b5173b501c9863cec59554224072ca34c1c827ec5fb8a257f97637b1
The hmac1 calls expects you to use the signing key as is, not to use an encoded version of the hex string representation of it.
You should be able to properly construct the Hmac object with this:
var hmac1 = Hmac(sha256, hex.decode(testSigninKey));
Here is a complete example of my flutter code, referring to the s3 signature creation example:
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
I know it's not perfect but it took me extremely long to figure it out. Maybe it helps someone.
import 'dart:convert';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
class AWS {
var _algorithm = ["X-Amz-Algorithm", "AWS4-HMAC-SHA256"];
final String _awsService = "s3";
final String _aws4Request = "aws4_request";
var _expires = ["X-Amz-Expires", "86400"];
var _signedHeaders = ["X-Amz-SignedHeaders", "host"];
var testbucket = "https://s3.amazonaws.com/examplebucket";
var testfilePath = "/test.txt";
var _testDate = ["X-Amz-Date", "20130524T000000Z"];
var _testDateymd = 20130524;
var _testRegion = "us-east-1";
var _testCredential = [
"X-Amz-Credential",
"AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request"
];
var testSecretkey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
testString() {
var httpMethod = "GET";
var canUri = testfilePath;
var canQueryStr = Uri.encodeQueryComponent(_algorithm[0]) +
"=" +
Uri.encodeQueryComponent(_algorithm[1]) +
"&" +
Uri.encodeQueryComponent(_testCredential[0]) +
"=" +
Uri.encodeQueryComponent(_testCredential[1]) +
"&" +
Uri.encodeQueryComponent(_testDate[0]) +
"=" +
Uri.encodeQueryComponent(_testDate[1]) +
"&" +
Uri.encodeQueryComponent(_expires[0]) +
"=" +
Uri.encodeQueryComponent(_expires[1]) +
"&" +
Uri.encodeQueryComponent(_signedHeaders[0]) +
"=" +
Uri.encodeQueryComponent(_signedHeaders[1]);
// <CanonicalQueryString>\n
// <CanonicalHeaders>\n
// <SignedHeaders>\n
// <HashedPayload>
var _canonicalRequest = httpMethod +
"\n" +
canUri +
"\n" +
canQueryStr +
"\n" +
"host:examplebucket.s3.amazonaws.com" +
"\n" +
"\n" +
"host" +
"\n" +
"UNSIGNED-PAYLOAD";
var bytes = utf8.encode(_canonicalRequest);
var _stringToSign = "AWS4-HMAC-SHA256" +
"\n" +
"20130524T000000Z" +
"\n" +
"20130524/us-east-1/s3/aws4_request" +
"\n" +
sha256.convert(bytes).toString();
print("String to sign: $_stringToSign");
// HEX und HMAC signature
List<int> _dateKey = utf8.encode("AWS4" + testSecretkey);
List<int> _dateMsg = utf8.encode(_testDateymd.toString());
Hmac dateHmac = Hmac(sha256, _dateKey);
Digest dateDigest = dateHmac.convert(_dateMsg);
String _dateRegionKey = dateDigest.toString();
List<int> _dateRegionMsg = utf8.encode(_testRegion.toString());
Hmac dateRegionHmac = Hmac(sha256, hex.decode(_dateRegionKey.toString()));
Digest dateRegionDigest = dateRegionHmac.convert(_dateRegionMsg);
String _dateRegionServiceKey = dateRegionDigest.toString();
List<int> _dateRegionServiceMsg = utf8.encode(_awsService.toString());
Hmac dateRegionServiceHmac =
Hmac(sha256, hex.decode(_dateRegionServiceKey.toString()));
Digest dateRegionServiceDigest =
dateRegionServiceHmac.convert(_dateRegionServiceMsg);
String _signingKey = dateRegionServiceDigest.toString();
List<int> _signingKeyMsg = utf8.encode(_aws4Request.toString());
Hmac _signingKeyHmac = Hmac(sha256, hex.decode(_signingKey.toString()));
Digest _signingKeyDigest = _signingKeyHmac.convert(_signingKeyMsg);
print("signing key: $_signingKeyDigest");
var _signatureKey = _signingKeyDigest.toString();
List<int> _signatureKeyMsg = utf8.encode(_stringToSign);
Hmac _signatureHmac = Hmac(sha256, hex.decode(_signatureKey));
var _signature = _signatureHmac.convert(_signatureKeyMsg);
print("Signature: $_signature");
}
}

AWS KMS signature returns Invalid Signature for my JWT

I am trying to generate a simple JWT, using ES256 using KMS. Everything looks fine to the naked eye. But I get "Invalid signature" when I test it through jwt.io. The code is quite simple:
public async Task<string> GenerateJwt(object payload)
{
var encodedHeader = Base64Encoder.EncodeBase64Url(JsonSerializer.Serialize(_header));
var encodedPayload = Base64Encoder.EncodeBase64Url(JsonSerializer.Serialize(payload));
var signatureData = Encoding.ASCII.GetBytes(encodedHeader + "." + encodedPayload);
var signature = await _signingService.Sign(signatureData);
var encodedSignature = Base64Encoder.ReplaceSpecialUrlCharacters(Convert.ToBase64String(signature));
return encodedHeader + "." + encodedPayload + "." + encodedSignature;
}
The SigningService looks something like this:
public async Task<byte[]> Sign(byte[] signatureData)
{
using var memoryStream = new MemoryStream(signatureData, 0, signatureData.Length);
var signRequest = new SignRequest()
{
KeyId = _signingKeyId,
Message = memoryStream,
SigningAlgorithm = SigningAlgorithmSpec.ECDSA_SHA_256
};
SignResponse signResponse = await _keyManagementService.SignAsync(signRequest);
return signResponse.Signature.ToArray();
}
_keyManagementService is an IAmazonKeyManagementService from AWSSDK.KeyManagementService 3.5.2.6
In KMS the key is set up like this:
Key Spec: ECC_NIST_P256
Key Usage: Sign and verify
Signing algorithms: ECDSA_SHA_256
Public key in KMS (using localstack)
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj7Cy/Gbx3jnuPdanuBSjuUmdnr7tQ/BcOytDlFoHWdNA1scc6RwNwqnNbmRE0BmwnlFNDVGxWU5oycTig8p0KQ==
Example on generated output
eyJhbGciOiJFUzI1NiJ9.eyJ0ZXN0MSI6MSwidGVzdDIiOiJ0d28iLCJ0ZXN0MyI6ZmFsc2V9.MEYCIQCiatnRhYGBKgdJj9LECe7mJ4bhhkVTvFSgpVI3Dm14pwIhAOrHAu0vqKvVwdgpAhaU7KOhiIBZdcEOuzfXrdXldCFQ
If it sign it with the built in tools (by just replacing the signatureData row above) with the same input I get it to validate in jwt.io.
var ecdsa = ECDsa.Create();
ecdsa.GenerateKey(ECCurve.NamedCurves.nistP256);
var signatureData = ecdsa.SignData(signatureData, HashAlgorithmName.SHA256);
Any input would be welcome as it feels like I've tested everything...
The problem was that KMS returns the signature in another format:
DER-encoded object as defined by ANS X9.62–2005
While the JWT should in the format R || S according to https://www.rfc-editor.org/rfc/rfc7515#appendix-A.3.1
So what I did as to add a convert method using BouncyCastle and called that before converting it to base64url:
private byte[] ConvertSignature(byte[] signature)
{
var asn1 = Asn1Object.FromByteArray(signature) as DerSequence;
if (asn1 == null)
return Array.Empty<byte>();
if (asn1.Count < 2)
return Array.Empty<byte>();
var r = asn1[0] as DerInteger;
var s = asn1[1] as DerInteger;
if (r == null || s == null)
return Array.Empty<byte>();
return Array.Empty<byte>()
.Concat(r.Value.ToByteArrayUnsigned())
.Concat(s.Value.ToByteArrayUnsigned())
.ToArray();
}

Creating an AES encrypted header value in Postman

To authenticate into a document retrieval API, I'm passing an encrypted string as a custom header value called ciphertext using a pre-request script. Is there a better/cleaner way of doing this?
var interface_name = "interface name";
var password = "12344576789";
var keySize = 256;
var ivSize = 128;
var iterations = 100;
var isoDate = new Date().toISOString();
var namedate = interface_name + '&' + isoDate;
pm.globals.set("interface_name", interface_name);
pm.globals.set("iterate", iterations);
pm.globals.set("strenth", keySize);
function encrypt(namedate, password) {
var salt = CryptoJS.lib.WordArray.random(ivSize / 8);
var key = CryptoJS.PBKDF2(password, salt, {
keySize: keySize / 32,
iterations: iterations
});
var iv = CryptoJS.lib.WordArray.random(ivSize / 8);
pm.globals.set("salt", salt.toString());
pm.globals.set("iv", iv.toString());
var encrypted = CryptoJS.AES.encrypt(namedate, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
var ciphertext = salt.toString() + iv.toString() + encrypted.toString();
return ciphertext;
}
var encrypted = encrypt(namedate, password);
pm.globals.set("ciphertext", encrypted);

Google Script, how can use variables with regex search?

Very inexperienced coder here, I have recently gotten a script working that uses regex to search for two different words occurring within a certain word limit. So I can search for "the" and "account" occurring within 10 words of each other, then my script prints the sentence it occurs in. However, my work requires me to search for lots of different work combinations and it has become a pain having to enter each word manually into the string /\W*(the)\W*\s+(\w+\s+){0,10}(account)|(account)\s+(\w+\s+){0,10}(the)/i; for example.
I would like to have something in the script where I can enter the words I want to search for just once, and they will be used in the string above. I have tried, what I think is, declaring variables like this:
var word1 = the
var word2 = account
/\W*(word1)\W*\s+(\w+\s+){0,10}(word2)|(word2)\s+(\w+\s+){0,10}(word1)/i;
But, again, very experienced coder so I'm a little out of my depth. Would really like something like the script snippet above to work in my full script listed below.
Here is my full working script without my attempt at declaring variables mentioned above:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var historySheet = ss.getSheetByName('master');
var resultsSheet = ss.getSheetByName('results');
var totalRowsWithData = historySheet.getDataRange().getNumRows();
var data = historySheet.getRange(1, 1, totalRowsWithData, 3).getValues();
var regexp = /\W*(the)\W*\s+(\w+\s+){0,10}(account)|(account)\s+(\w+\s+){0,10}(the)/i;
var result = [];
for (var i = 0; i < data.length; i += 1) {
var row = data[i];
var column = row[0];
if (regexp.exec(column) !== null) {
result.push(row); }}
if (result.length > 0) {
var resultsSheetDataRows = resultsSheet.getDataRange().getNumRows();
resultsSheetDataRows = resultsSheetDataRows === 1 ? resultsSheetDataRows : resultsSheetDataRows + 1;
var resultsSheetRange = resultsSheet.getRange(resultsSheetDataRows, 1, result.length, 3);
resultsSheetRange.setValues(result);}}
I tried this solution but not sure I have done it correctly as it only enters results in logs and not printing in the "results" sheet:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var historySheet = ss.getSheetByName('Sheet1');
var resultsSheet = ss.getSheetByName('Results1');
var totalRowsWithData = historySheet.getDataRange().getNumRows();
var data = historySheet.getRange(1, 1, totalRowsWithData, 3).getValues();
const regexpTemplate = '\W*(word1)\W*\s+(\w+\s+){0,10}(word2)|(word2)\s+(\w+\s+){0,10}(word1)';
var word1 = 'test1';
var word2 = 'test2';
var regexpString = regexpTemplate.replace(/word1/g, word1).replace(/word2/g, word2);
var regexp = new RegExp(regexpString, 'i');
Logger.log(regexp); // /W*(the)W*s+(w+s+){0,10}(account)|(account)s+(w+s+){0,10}(the)/i
var result = [];
for (var i = 0; i < data.length; i += 1) {
var row = data[i];
var column = row[0];
if (regexp.exec(column) !== null) {
result.push(row); }}
if (result.length > 0) {
var resultsSheetDataRows = resultsSheet.getDataRange().getNumRows();
resultsSheetDataRows = resultsSheetDataRows === 1 ? resultsSheetDataRows : resultsSheetDataRows + 1;
var resultsSheetRange = resultsSheet.getRange(resultsSheetDataRows, 1, result.length, 3);
resultsSheetRange.setValues(result);}}
Use the RegExp contructor.
const regexpTemplate = '\\W*(word1)\\W*\\s+(\\w+\\s+){0,10}(word2)|(word2)\\s+(\\w+\\s+){0,10}(word1)';
var word1 = 'the';
var word2 = 'account';
var regexpString = regexpTemplate.replace(/word1/g, word1).replace(/word2/g, word2);
var regexp = new RegExp(regexpString, 'i');
Logger.log(regexp); // /\W*(the)\W*\s+(\w+\s+){0,10}(account)|(account)\s+(\w+\s+){0,10}(the)/i
You can put this into a function to easily generate your new regular expression whenever you want to update the words.
/**
* Generate the regular expression with the provided words.
* #param {String} word1
* #param {String} word2
* #returns {RegExp}
*/
function generateRegExp(word1, word2) {
const regexpTemplate = '\\W*(word1)\\W*\\s+(\\w+\\s+){0,10}(word2)|(word2)\\s+(\\w+\\s+){0,10}(word1)';
var regexpString = regexpTemplate.replace(/word1/g, word1).replace(/word2/g, word2);
return new RegExp(regexpString, 'i');
}
/**
* Test the generateRegExp() function.
*/
function test_generateRegExp() {
var word1 = 'the';
var word2 = 'account';
var regexp = generateRegExp(word1, word2); // /\W*(the)\W*\s+(\w+\s+){0,10}(account)|(account)\s+(\w+\s+){0,10}(the)/i
// Use regexp just as you do in your script
// i.e. if (regexp.exec(column) !== null) { result.push(row); }
}
Your final script could look something like this.
function printSentences() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var historySheet = ss.getSheetByName('Sheet1');
var resultsSheet = ss.getSheetByName('Results1');
var totalRowsWithData = historySheet.getDataRange().getNumRows();
var data = historySheet.getRange(1, 1, totalRowsWithData, 3).getValues();
var result = [];
var regexp = generateRegExp("the", "account");
for (var i = 0; i < data.length; i += 1) {
var row = data[i];
var column = row[0];
if (regexp.exec(column) !== null) {
result.push(row);
}
}
if (result.length > 0) {
var resultsSheetDataRows = resultsSheet.getDataRange().getNumRows();
resultsSheetDataRows = resultsSheetDataRows === 1 ? resultsSheetDataRows : resultsSheetDataRows + 1;
var resultsSheetRange = resultsSheet.getRange(resultsSheetDataRows, 1, result.length, 3);
resultsSheetRange.setValues(result);
}
}
/**
* Generate the regular expression with the provided words.
* #param {String} word1
* #param {String} word2
* #returns {RegExp}
*/
function generateRegExp(word1, word2) {
const regexpTemplate = '\\W*(word1)\\W*\\s+(\\w+\\s+){0,10}(word2)|(word2)\\s+(\\w+\\s+){0,10}(word1)';
var regexpString = regexpTemplate.replace(/word1/g, word1).replace(/word2/g, word2);
return new RegExp(regexpString, 'i');
}

Regex in Google App Script to enclose each word inside an Array inside quotes

For example I want to enclose each word in the following array inside quotes.
{seguridad=0, funcionalidad=1, instalaciones=si, observaciones=si,
areas=Pasillos, limpieza=no, pintura=tal vez}
Into:
{"seguridad"="0", "funcionalidad"="1", "instalaciones"="si",
"observaciones"="si", "areas"="Pasillos", "limpieza"="no",
"pintura"="tal vez"}
This is my unsuccesful script so far.
function Enclose() {
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("1iXQxyL3URe1X1FgbZ76mEFAxLnxegyDzXOMF6WQ5Yqs"));
var sheet = doc.getSheetByName("json");
var sheet2 = doc.getSheetByName("tabla de frecuencias");
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var prelast = sheet.getRange("A1:A").getValues();
var last = prelast.filter(String).length;
var json = sheet2.getRange("B11").getValues();
var regExp = new RegExp("/[\w]+", "g");
/* var match = json.replace(regExp,""); */
var match = regExp.exec(match);
sheet2.getRange("C11").setValue("\"" + match + "\"");
}
You may try the following approach :
First you wrap all , and = by quotes "" by using the following regex:
/(\s*[,=]\s*)/
Then you replace the opening brackets separately using the following two regex:
/(\s*{)/gm
/(\s*})/gm
const str = `{seguridad=0, funcionalidad=1, instalaciones=si, observaciones=si, areas=Pasillos, limpieza=no, pintura=tal vez}`;
var result = str.replace(/(\s*[,=]\s*)/gm,`"$1"`);
result=result.replace(/(\s*{)/gm,`$1"`);
result=result.replace(/(\s*})/gm,`"$1`);
console.log(result);
How about this sample?
Sample script :
var json = "{seguridad=0, funcionalidad=1, instalaciones=si, observaciones=si, areas=Pasillos, limpieza=no, pintura=tal vez}";
var res = json.replace(/(\d+|[a-zA-Z]+)=(\d+|[a-zA-Z\s]+)/g, "\"$1\"=\"$2\"");
Logger.log(res)
Result :
var json = "{seguridad=0, funcionalidad=1, instalaciones=si, observaciones=si, areas=Pasillos, limpieza=no, pintura=tal vez}";
var res = json.replace(/(\d+|[a-zA-Z]+)=(\d+|[a-zA-Z\s]+)/g, "\"$1\"=\"$2\"");
console.log(res)
When this is reflected to your script, the modified script is as follows.
Modified script :
function Enclose() {
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("1iXQxyL3URe1X1FgbZ76mEFAxLnxegyDzXOMF6WQ5Yqs"));
var sheet = doc.getSheetByName("json");
var sheet2 = doc.getSheetByName("tabla de frecuencias");
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var prelast = sheet.getRange("A1:A").getValues();
var last = prelast.filter(String).length;
var json = sheet2.getRange("B11").getValue();
// var regExp = new RegExp("/[\w]+", "g");
// /* var match = json.replace(regExp,""); */
// var match = regExp.exec(match);
match = json.replace(/(\d+|[a-zA-Z]+)=(\d+|[a-zA-Z\s]+)/g, "\"$1\"=\"$2\"");
sheet2.getRange("C11").setValue("\"" + match + "\"");
}