AES-128-CBC decpription return wrong value - aes

I tried to create an AES-128-CBC decryption over javascript
Here I did so far:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
<script>
var rawStr = "MyPassword";
var secret = 'EL12ec#REteLe(0M';
var wordArray = CryptoJS.enc.Utf8.parse(rawStr);
var base64 = CryptoJS.enc.Base64.stringify(wordArray);
var encrypted = '' + CryptoJS.AES.encrypt(base64, secret);
console.log('base64:', base64);
console.log('encrypted:', encrypted);
</script>
But the value I got is: TXlQYXNzd29yZA==
The correct value is: S9bEDxeu/jr+8CdRkiUEog== based on this online encryption tools: https://www.devglan.com/online-tools/aes-encryption-decryption
Anyone can help me how to achieved this to get same result encryption same like devglan tools?
Thanks,

To reproduce the result of the website, the following has to be considered:
The key must be passed to CryptoJS.AES.encrypt as WordArray. Otherwise it is interpreted as a passphrase, here.
The CBC mode (CryptoJS default, here) requires an IV, which must be passed to CryptoJS.AES.encrypt as WordArray (if no IV is specified on the website, a 0-vector is implicitly used).
The return value of CryptoJS.AES.encrypt is a CipherParams object, which encapsulates the ciphertext among other things, here.
var rawStr = "MyPassword";
var secret = CryptoJS.enc.Utf8.parse('EL12ec#REteLe(0M');
var iv = CryptoJS.enc.Utf8.parse('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0');
var encrypted = CryptoJS.AES.encrypt(rawStr, secret, {iv: iv});
console.log('Output:', CryptoJS.enc.Base64.stringify(encrypted.ciphertext)); // Output: S9bEDxeu/jr+8CdRkiUEog==
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/crypto-js.min.js"></script>

Related

Azure Data Factory Rest API - With AccountCode, APIKey & Token

I have a use case wherein, I need to connect to an API for data request.
The API requires a valid token to process the requests.
To generate the token, I have a accountCode & secret key
Assume BaseURL as
BaseURL - http://api.xxxxx.com/{accountCode}/data (Value of account needs to be passed)
**Below script in Python/Java needs to be run to fetch the dateToken & token
If we use Python 3.6 or above. Below is the code -**
--START-- {
import time
import requests
from hashlib import md5
account_code = "<account_name>"
key = "<api_key>"
actual_unix_time = int(time.time_ns() / 1000) # in milliseconds
TTL = 31536000000 # for 1 year
expiration_time = actual_unix_time + TTL
base_url = "https://api.xxxxx.com"
url = f"/{account_code}/data?fromDate=last6Hours&granularity=minute&type=ALL%2CVOD%2CLIVE&operation=reduceJoin&metrics=bufferratio"
pre_url = f"{url}&dateToken={expiration_time}"
token_generated = md5(f"{pre_url}{key}".encode('utf-8'))
token_value = token_generated.hexdigest()
request_url = f"{base_url}{pre_url}&token={token_value}"
response = requests.get(request_url)
print(response)
print(response.text)
} --END--
- If we use Java. Below is the code -
--START-- {
var key = pm.environment.get("NPAW-API-KEY");
var base_url = "https://api.xxxxx.com";
var url = pm.request.url.toString();
var path = url.replace(base_url, '');
var pre_url = pm.variables.replaceIn(path);
var moment = require('moment');
var actual_unix_time = moment().unix()*1000;
var TTL = 31536000000
var expiration_time = (actual_unix_time + TTL);
var pre_url = pre_url+"&dateToken="+expiration_time;
var token_generated = CryptoJS.MD5(pre_url + key).toString();
var token_value = token_generated;
var request_url = (base_url+pre_url+'&token='+token_value).toString();
}--END--
Example of how the final URL - https://api.xxxxx.com/kb-vivek/data?fromDate=today&granularity=hour&type=ALL,VOD,LIVE&operation=reduceJoin&metrics=views,playtime&dateToken=1699016056000&token=7a9c97a4d4f108d1d32be2f7f8d00731
I tried to use Postman, wherein, I could pass the above script in the Pre-Request script and set environment variables for accountCode & Secret Key and I was able to achieve the result as desired.
Question: How can I achieve this in Azure Data Factory?
To achieve the requirement, we need to use a combination of set variables and dataflows (to generate md5 hex string and store final url in a file).
First, I have created 4 parameters with values as shown below:
base_url: https://api.xxxxx.com
account_code: <account_name>
key: <api_key>
TTL: 31536000000
First, I have created a variable to build url. I used the following dynamic content:
/#{pipeline().parameters.account_code}/data?fromDate=last6Hours&granularity=minute&type=ALL%2CVOD%2CLIVE&operation=reduceJoin&metrics=bufferratio
Next, I have built the pre_url with the following dynamic content:
#{variables('url')}&dateToken=#{add(div(sub(ticks(utcNow()), ticks('1970-01-01')),10),31536000000)}
Now, to encode the string and convert it to md5 hex string, I have used dataflow. I have passed base_url, pre_url and key to the dataflow from the pipeline.
I have taken a sample csv file with only one row from blob storage (the data in this file does not matter but make sure it has 1 row only).
I have created a derived column to create final URL by concatenating base_url, pre_url and encoded md5 hex string. Use the following content:
$base_url+$pre_url+'&token='+md5(encode(concat($pre_url,$key)))
Now I am writing this data to a file by using output to single file option in the sink settings.
When I debug the pipeline, the file will be written to my storage account. The contents of the file will be as shown below:
NOTE:
Now since you want to generate date token once and use it for a year, I have written the data to a file.
You run this pipeline once and generate a file with required URL (as above). Anytime you want to access this URL, you can use look up activity to access the URL anywhere required.
I have used utcNow() to generate dateToken. But if you have any specific date in mind, you can simply use that in the correct format (in place of utcNow()).

Spotify PKCE in Dart/Flutter: "code_verifier was incorrect"

Using the Authorization Code Flow with PKCE of the Spotify-API I am getting the error that my code_verifier is incorrect, which has to be an encoding problem from what I know by now.
{"error":"invalid_grant","error_description":"code_verifier was incorrect"}
This is the original code I wrote:
String getAuthUrl() {
code = getRandomString(128);
// saveToPrefs("verfifier_code", code);
var hash = sha256.convert(ascii.encode(code));
String code_challenge = base64Url.encode(hash.bytes);
return Uri.parse(
"https://accounts.spotify.com/authorize?response_type=code&client_id=${widget.client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Fauth&scope=user-top-read&code_challenge=$code_challenge&code_challenge_method=S256")
.toString();
}
This is how I understand the Spotify-Authorisation-Guide (https://developer.spotify.com/documentation/general/guides/authorization-guide/).
After finding this post (https://stackoverflow.com/a/63174909/14266484) I tried porting the fix to Dart but failed. As far as I understand it the code hashes the in ascii encoded code_verifier and then uses btoa() to convert it into ascii again. This function also seems to do base64 (but not base64Url, maybe this is why certain parts have to be replaced manually?).
String getAuthUrl() {
// also tried static verifier_codes for debugging, so the getRandomString() function is working properly
code = getRandomString(128);
// saveToPrefs("verfifier_code", code);
var hash = sha256.convert(ascii.encode(code));
// this does not work with either base64 or base64Url
String code_challenge = base64.encode(hash.bytes).replaceAll(RegExp(r"/\+/g"), '-').replaceAll(RegExp(r"/\//g"), '_').replaceAll(RegExp(r"/=+$/"), '');
return Uri.parse(
"https://accounts.spotify.com/authorize?response_type=code&client_id=${widget.client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Fauth&scope=user-top-read&code_challenge=$code_challenge&code_challenge_method=S256")
.toString();
}
I also tried different ways of encoding:
-Using String.codeUnits (But this is using UTF-16)
-Getting a String for the sha256-function aswell the base64(-Url)-function with String.fromCharCodes() (which should be using ASCII?)
-Switching between ASCII and UTF-8 (Which should not make a difference in that case as my verifier_code is made up of ASCII-Characters only)
EDIT:
To make the requests I use:
var res = await http.post(endpoint, body: {"client_id":widget.client_id, "grant_type":"authorization_code", "code":value, "redirect_uri":"http://localhost/auth", "code_verifier":code});
After some more research I found out that the important thing that is happening is that the "=" at the end of the challenge has to be removed (Shouldn't base64Url do that?). Anyways, that is the working code:
EDITED CODE:
String getAuthUrl() {
code = getRandomString(128);
var hash = sha256.convert(ascii.encode(code));
String code_challenge = base64Url.encode(hash.bytes).replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_");
return Uri.parse(
"https://accounts.spotify.com/authorize?response_type=code&client_id=${widget.client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Fauth&scope=user-top-read&code_challenge=$code_challenge&code_challenge_method=S256")
.toString();
}
EDIT:
Further "+" has to be replaced with "-" and "/" with "_"!

crypto-js decrypt from Hex

I am trying to make a JavaScript function with package crypto-js to decode AES (CBC mode).
I input the data in an online decoding tool and it decrypted correctly, so I am sure the following data is correct, but I just can't reproduce it by JavaScript.
Here is the online decrypting (so I'm sure the data, key, iv are correct): http://aes.online-domain-tools.com/link/deb718giF4dUxZylq/
My code with crypto-js#3.1.8:
// data, key, iv are all Hex
var data = "bd6e0a73147a2c224c7c20346d0e9a138b744a5d94463cdff6dbb965055f974f097104399d2c40af2f0ac667f3857e70e9703bf27f6411f7e97c3449e8921f3c98e665914689b4b77b5bbcc8d8bc319e680eb89eedb1c25178923ae57fb3fb476755d6009f1aed88fffcb9b2ed3b4cf6f23d9c4c56da1dde6619e45a8d6f06412853ae1941cf554b6824112a913750a7485ed67fb38b950411310410de998f2597c2fcc81a305b0df369f54b75426176";
var key = 'befce5c6da98837ea421811c832817ae';
var iv = "a884a7edd5d06a48d6da9ad11fd36a75";
// transfer Hex to WordArray
var _data = CryptoJS.enc.Hex.parse(data);
var base64_data = _data.toString(CryptoJS.enc.Base64);
var _key = CryptoJS.enc.Hex.parse(key);
var _iv = CryptoJS.enc.Hex.parse(iv);
decrypted = CryptoJS.AES.decrypt(
base64_data, // pass base64
_key, // pass WordArray
{iv: _iv, // pass WordArray
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
})
console.log(decrypted.toString(CryptoJS.enc.Utf8));
// out put fail to match Utf8
It output Error: Malformed UTF-8 data
The decoded string should be: (the link is not important)
https://emogo-media-testing.s3.amazonaws.com/1503342403787_blob?AWSAccessKeyId=AKIAI5MUDCK6XYWKGAKA&Expires=1534882403&Signature=t1PFesQuOpOlIMKoOqje%2Bs7I%2Fhg
Any hint is appreciated. Thank you!
I know it has been a while since you asked the question but I will respond just so the next person does not stumble upon an unanswered question.
Your code works fine, it decrypts AES.CBC encrypted data correct, the problem lies with your input data.
Your encrypted data string should have looked like:
80b7c4881334675693ef9c95259e70b24d0736e98f8424233d5e37f353261c2a589287bc3f675449f7d8ed4e2289a4c06b22d7f83efc09cfb72abe3a76e193a8efbdc968232d29b9b58135bfa24d51e60e34791f652a0aa806d0be7734dd61a930a30c99f31f08740cdb182af07b19d5b4274deb958d984b3ccb9d6e2be0cfa3a026dd6b734dbf1dd3635bc7bcceface9c55dfb9455ca834a6dbd1aa0f3c23923ce6aeba59acbc80d681fee73487b9004496540830d44102b94e35eac291c4e3b8c9ac168ae799e46cde45ee652415ae69992d0f7527045fd42b82e9e6946cfb2dbcc3b93f19ff0e5035ab12250f7a917975b2f7c069cbd8a0ba0d94b318634a
for this example to work correctly.
The key you used is not a hex string but a text string. Your online example is no longer valid but I figured it out after a couple of tries.
If change the following line:
var _key = CryptoJS.enc.Hex.parse(key);
to:
var _key = CryptoJS.enc.Utf8.parse(key);
Your code example will work fine with your original data string.
When you decrypted the text on http://aes.online-domain-tools.com/ you probably had the plaintext textbox selected instead of hex for your key input.

How can we genetrate the secret/key to sign in JWT so that it can be used?

I want to use the JWT secretorkey in my code.So I need to store it at a different place.How can I generate it?
It is used in the code as follows:
This secret is present in config/auth
module.exports = {
'secret': 'eypZAZy0CY^g9%KreypZAZy0CY^g9%Kr', //how will I generate this??
}
In config/passport.js
var config = require('./auth');
var jwtOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeader(),
secretOrKey: config.secret
};
Assuming you just need a crypto random string you could for example use this
https://www.grc.com/passwords.htm.
In nodejs you can use crypto.randomBytes (https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) to generate cryptographically strong pseudo-random data.
In .Net you can use RngCryptoServiceProvider to generate random sequences
Or if it is one time you could just close your eyes and type a bunch of "random" characters on the keyboard :)

Kraken API MATLAB client invalid signature error

I'm trying to do some authenticated calls to Kraken private endpoints but without success. I'm still getting an error EAPI:Invalid signature.
Does anybody know what's wrong?
Here's the code:
function [response,status]=kraken_authenticated(uri,postdata)
% test uri='0/private/AddOrder'
% test postdata='&pair=XBTEUR&type=buy&ordertype=limit&price=345.214&volume=0.65412&leverage=1.5&oflags=post'
url=['https://api.kraken.com/',uri];
% nonce
nonce = num2str(floor((now-datenum('1970', 'yyyy'))*8640000000));
[key,secret]=key_secret('kraken');
% 1st hash
Opt.Method = 'SHA-256';
Opt.Input = 'ascii';
sha256string = DataHash(['nonce=',nonce,postdata],Opt);
% 2nd hash
sign = crypto([uri,sha256string], secret, 'HmacSHA512');
header_1=http_createHeader('API-Key',key);
header_2=http_createHeader('API-Sign',char(sign));
header=[header_1 header_2];
[response,status] = urlread2(url,'POST',['nonce=',nonce,postdata],header);
end
Crypto function is in another file:
function signStr = crypto(str, key, algorithm)
import java.net.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.apache.commons.codec.binary.*
keyStr = java.lang.String(key);
key = SecretKeySpec(keyStr.getBytes('UTF-8'), algorithm);
mac = Mac.getInstance(algorithm);
mac.init(key);
toSignStr = java.lang.String(str);
signStr = java.lang.String(Hex.encodeHex( mac.doFinal( toSignStr.getBytes('UTF-8'))));
end
I've also tried
sign = crypto([uri,sha256string], base64decode(secret), 'HmacSHA512');
but without success.
This is guide for authenticated call HTTPS Header:
API-Key = API key
API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
This is guide for authenticated call POST Data:
nonce = always increasing unsigned 64 bit integer
otp = two-factor password (if two-factor enabled, otherwise not required)
I've tried to pass "nonce" parameter or all parameters in "postdata" to POST data but without success.
Thanks for help.
The problem is in function crypto here:
keyStr = java.lang.String(key);
key = SecretKeySpec(keyStr.getBytes('UTF-8'), algorithm);
As the base64 encoded private key from kraken is not necessarily UTF-8 encoded, you cannot use UTF-8 encoding to extract the key and pass UTF-8 string to the SecretKeySpec function. You need to use byte array instead.
Similar issues
https://code.google.com/p/google-apps-script-issues/issues/detail?id=5113
https://code.google.com/p/google-apps-script-issues/issues/detail?id=3121
Solution for javascript
github.com/Caligatio/jsSHA