Flutter and dart convert string to md5 then call as a string - flutter

For an api I am using, I have to convert a string password and a salt to a md5 string and call that string in a url post request,
my code looks like this:
generateMd5(String data) {
var content = new Utf8Encoder().convert(sp);
var md5 = crypto.md5;
var digest = md5.convert(content);
return digest.toString();
}
problem is i can't call it as a string. when i put "print(data)" it says its an Undefined name.

You need a method like this for your salted password token.
String makeToken(String password, String salt) =>
md5.convert(utf8.encode(password + salt)).toString().toLowerCase();
Calling print(makeToken('sesame', 'c19b2d')); yields 26719a1196d2a940705a59634eb18eab as shown in the test vector.
Supply the token as the t parameter and the salt as the s parameter of your API call.
You might find the following useful for your salt creation:
final _random = Random();
String randomToken(int length) => String.fromCharCodes(
List.generate(length, (_) {
var ch = _random.nextInt(52);
if (ch > 25) {
ch += 6;
}
return ch + 0x41;
}),
);
String newSalt() => randomToken(6);

Related

sign okex api in flutter

i have problem to sign api for okex
,in document of okex:
The OK-ACCESS-SIGN header is generated as follows:
Create a prehash string of timestamp + method + requestPath + body
(where + represents String concatenation). Prepare the SecretKey. Sign
the prehash string with the SecretKey using the HMAC SHA256. Encode
the signature in the Base64 format. Example:
sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp +
'GET' + '/users/self/verify', SecretKey))
The timestamp value is the same as the OK-ACCESS-TIMESTAMP header with
millisecond format of ISO, e.g. 2020-12-08T09:08:57.715Z.
The request method should be in UPPERCASE: e.g. GET and POST.
The requestPath is the path of requesting an endpoint.
Example: /api/v5/account/balance
The body refers to the String of the request body. It can be omitted
if there is no request body (frequently the case for GET requests).
method i made fo sign is:
dynamic _getSign(String timestamp, String methodType, String url, String body) {
if (body.isEmpty) {
body = "";
}
String message = timestamp + methodType.toUpperCase() + url + body;
var hmacSha256 = Hmac(sha256, utf8.encode(oKSecretKey));
var mac = hmacSha256.convert(utf8.encode(message));
// var a = mac.bytes;
var a = base64Url.encode(mac.bytes);
print(a);
return a;
}
Future<String> getAccountInfo() async {
try {
String timestamp = getServerTime();
String url = '/api/v5/account/balance';
Response response = await OKEXApi.dio.get(url,
queryParameters: {},
options: Options(headers: {
"OK-ACCESS-KEY": oKACCESSKEY,
"OK-ACCESS-PASSPHRASE": oKACCESSPASSPHRASE,
"OK-ACCESS-TIMESTAMP": timestamp,
"OK-ACCESS-SIGN": _getSign(timestamp, "GET", url, ""),
'Accept': 'application/json',
'Content-type': 'application/json',
}));
print(response.data);
return response.data;
} on DioError catch (e) {
return e.error;
}
}
and for timestamp
String getServerTime() {
DateTime now = DateTime.now().toUtc();
String isoDate = now.toIso8601String();
return isoDate;
}
And when i send data, response is:
{"msg":"Invalid Sign","code":"50113"}
The spec says:
OK-ACCESS-TIMESTAMP header with millisecond format of ISO, e.g.
2020-12-08T09:08:57.715Z
Truncate the microseconds away like this:
final now = DateTime.now().toUtc();
final microlessNow = now.subtract(Duration(microseconds: now.microsecond));
final isoDate = microlessNow.toIso8601String();
print(isoDate);

Escaping From "/" Character in Dart Encryption

I have an encryption class in Dart, which will encrypt User ID for posting it to MariaDB table with REST (Post Request, ? and * is placeholder, these are different in my real code.):
import 'package:encrypt/encrypt.dart';
//import 'dart:convert' as convert;
class Security {
///Key
static final _key =
Key.fromUtf8('********************************'); //32 chars
static final iv = IV.fromUtf8('????????????????'); //16 chars
///encrypt, [text] is data.
static String encryptMyData(String text) {
final e = Encrypter(AES(_key, mode: AESMode.cbc));
final encryptedData = e.encrypt(text, iv: iv);
return encryptedData.base64;
}
///decrypt, [text] is data.
static String decryptMyData(String text) {
final e = Encrypter(AES(_key, mode: AESMode.cbc));
final decryptedData = e.decrypt(Encrypted.fromBase64(text), iv: iv);
return decryptedData;
}
}
Sometimes, "/" char coming in encrypted ID, which causes 404 and 405 errors on POST request. Because "/" is HTML routing character.
My POST code is:
///Adds an user item to database via decoding / encoding the JSON value.
///[name] is name, [surname] is surname, [uid] is user id, [type] is user role, [debt] is user debt, [paucode] is pay code.
static Future<bool> addUserToDatabase(String name, String surname, String uid,
double debt, String paycode, int type) async {
try {
if (name != null &&
surname != null &&
uid != null &&
debt != null &&
paycode != null &&
type != null) {
var addingUser = User(name.toLowerCase(), surname.toLowerCase(),
Security.encryptMyData(uid), type, debt, paycode);
print('This user will be added:\n------\n$addingUser\n-----------\n');
var uri = Uri.https('localhost:5001',
'User/username=${addingUser.userName}&surname=${addingUser.userSurname}&id=${addingUser.personID}&debt=${addingUser.userDebt}&type=${addingUser.type}&paycode=${addingUser.payCode}');
print('The URI: $uri');
var request = await http.post(uri);
print(
'The response:\n----\n- ${request.body}\n Status Code: ${request.statusCode}\n----\n');
if (request.statusCode == 201 || request.statusCode == 200) {
// If the server did return a 201 Created response,
// then return value.
return true;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception(
'Failed to add user. Status Code: ${request.statusCode}');
}
}
return false;
} catch (e) {
print('An error occurred - $e');
return false;
}
}
How I escaping from "/" character in Dart encryption ? I don't want this character in the encrypted string. Thanks.
encryptMyData() Base64 encodes the data. The Base64 alphabet contains alphanumeric characters and the characters /, + and = (padding), where the last three have a special meaning and are therefore reserved in the context of URIs.
A simple way to mask these characters would be to URL encode the Base64 encoded strings with Uri.encodeComponent(). Accordingly, URL decoding with Uri.decodeComponent() must be performed before Base64 decoding:
var base64Data = 'EBES/+7dzA==';
var urlEnc = Uri.encodeComponent(base64Data);
print(urlEnc); // EBES%2F%2B7dzA%3D%3D
// Apply in URL
var urlDec = Uri.decodeComponent(urlEnc);
print(urlDec); // EBES/+7dzA==
Alternatively, Base64url can be applied instead of Base64. Base64url uses the characters _ and - instead of / and + as well as optional padding. Unlike / and +, _ and - are not reserved for URIs.
Base64url is supported in Dart by base64Url.encode(). The padding is applied, but can be removed explicitly (e.g. with replaceAll('=','')). Decoding is possible with base64Url.decode() (after the padding has been added). Alternatively, base64Url.normalize() can be used to convert to Base64 (which automatically adds the padding) and base64.decode() can be applied for Base64 decoding:
var b64urlEnc = base64Url.encode([16, 17, 18, 255, 238, 221, 204]);// [0x10, 0x11, 0x12, 0xff, 0xee, 0xdd, 0xcc]
print(b64urlEnc); // EBES_-7dzA==
var b64urlEncNoPadding = b64urlEnc.replaceAll('=','');
print(b64urlEncNoPadding); // EBES_-7dzA
// Apply in URL
var base64Enc = base64Url.normalize(b64urlEncNoPadding);
print(base64Enc); // EBES/+7dzA==
var base64Dec = base64.decode(base64Enc);
print(base64Dec); // [16, 17, 18, 255, 238, 221, 204]
Optionally, for already Base64 encoded data, the characters / and + can be replaced by _ and - and the padding (=) can be removed.

Function to iterate trough comma separated hex strings and decode them in dart/flutter

I need a little help with a function in dart/flutter I am trying to write.
There are bunch of HEX encoded strings separated by comma and joined together in one String.
For example:
String input = 'HexEncodedStr1,HexEncodedStr2,HexEncodedStr3'
I need to decode each of those strings and output them in the same comma separated form:
String output = 'HexDecodedStr1,HexDecodedStr2,HexDecodedStr3'
Currently, I am using hex.dart package as string decoder but I am struggling to separate each encoded string before decoding it with hex.dart:
import 'package:hex/hex.dart';
//The decode function
String decode(hexString) {
if (hexString != "") {
hexString = HEX.decode(hexString);
return hexString;
} else {
return "N/A";
}
}
void main() {
String test = decode('776f726c64,706c616e65740d0a');
print(test); //world,planet
}
How about splitting the string and joining decoded parts afterwards?
void main() {
final decoded = '776f726c64,706c616e65740d0a'
.split(',')
.map(decode)
.join(',');
print(decoded); //world,planet
}
You could use string.split(",");
https://api.flutter.dev/flutter/dart-core/String/split.html
String input = 'HexEncodedStr1,HexEncodedStr2,HexEncodedStr3'
var inputSplit = input.split(",");
Now you have a list of substring. I think that you can then you a for loop or foreach.
inputSplit.forEach((element) => print(decode(element);));
or:
for(var i = 0; i < inputSplit.length; i++)
{
var oneHex = decode(inputSplit[i]);
print(oneHex);
}

How to decrypt AES 256 CBC with Dart

I want to convert below PHP script to dart i tried a lot case but nothing help me.
I have tried following code; But throw an exception here encrypter.decrypt method.
import 'package:encrypt/encrypt.dart' as EncryptPack;
import 'package:crypto/crypto.dart' as CryptoPack;
import 'dart:convert' as ConvertPack;
void main(List<String> arguments) {
var decrypt = extractPayload('$encryptedResopnse');
print(decrypt);
}
String extractPayload(String encryptedResopnse) {
if (encryptedResopnse == null) {
return '';
}
var separated = encryptedResopnse.split(':');
var secret = 'abcd123';
var data = ConvertPack.base64Decode(separated[0].trim());
var iv = CryptoPack.sha256.convert(data).toString().substring(0, 16);
var salt = CryptoPack.sha256.convert(data).toString().substring(16, 32);
var cipherText = CryptoPack.sha256.convert(data).toString().substring(64);
print('cipherText : ${cipherText}');
var ivObj = EncryptPack.IV.fromBase64(iv);
var generator = PBKDF2(hashAlgorithm: CryptoPack.sha1);
var hash = generator.generateBase64Key(secret, salt, 2048, 32);
print('hash : $hash');
var keyObj = EncryptPack.Key.fromBase64(hash);
final encrypter = EncryptPack.Encrypter(
EncryptPack.AES(keyObj, mode: EncryptPack.AESMode.cbc)); // Apply CBC mode
print(cipherText);
var firstBase64Decoding = cipherText; // First Base64 decoding
print(firstBase64Decoding);
final decrypted = encrypter.decrypt(
EncryptPack.Encrypted.fromBase64(firstBase64Decoding),
iv: ivObj);
return decrypted;
}
for demo content ;
Initialize the aes_secret
$aes_secret = '123456ac';
Demo content;
$encryptedResopnse = "dBluiiVaHxhRcWJPaEip9kCGXDwufk3mFp8Xe9ioh9UKu6xL+CHUZrKvuf3xI7P1vFpvyyJ2Vz2Q3ieLEuRHk7NOinZU82FNdE3SOc9D2JTUFkif5ye3rVfQ7O39DpBnV41CduEP0OsASA8cr/RChqhulVHsaw6oUP0mg79M3Jlnpbab0EqlWRQx3k85rcajmov4cYLmsja++p2Lyw/BgOTKDf/yw3NWiK73Ot4P3C6urUiFNUCQTaOHCas1Sa8Wl0udQo1viyApuCE9+Ll1SGnUu26uNy5RR55IFLVnAHuIOBDePjdAw3DapAtLFnSd+FrVjYcUuevMMliSy3PHiZU66qdyx8YSn13tYH6KGFxC/kvPsi5dLGorQ1TdNR5fxZGRPNQXEEIwWYSiF8LA0AJzVqpRoXs9PkEseCUnH1Sj5sBQgXQc0RA8vHWf3n2X/cABLEWaRHHlBlZjqjJXl0uKSgAWC3JoelABGSuSCvL3GJhn9SuSV6+jCOftb6UCmw7LzalKB7UNIQPJ1vMtKl3+38RKDwp7a4xpdlln+IPp+R2aGuobuhk9ySSJYN3GCn7MoC/uaCAR0aEYsIHP1BQ+UgOPOsQFZEVdKMrFLJsJ3HtQ1fQxqpPQ13TClWCOyZu+w+1q4W+8CBJuI4l4Em+91";
class AesEncryption {
private static $encryptionMethod = 'aes-256-cbc';
private static $blockSize = 16;
private static $keySize = 32; // in bytes - so 256 bit for aes-256
private static $iterations = 2048;
public static function sign($data, $key) {
return hash_hmac('sha256', $data, $key);
}
/**
* #param string $encryptedContent
* #param string $secret
* #return string
*/
public static function decrypt(string $encryptedContent, string $secret) {
if (!$encryptedContent) {
return "";
}
// Separate payload from potential hmac
$separated = explode(":", trim($encryptedContent));
// Extract HMAC if signed
$hmac = (isset($separated[1])) ? $separated[1] : null;
// Convert data-string to array
$data = base64_decode($separated[0]);
// Then we remove the iv and salt to fetch the original text
$iv = substr($data, 0, self::$blockSize);
//echo($iv);
$salt = substr($data, self::$blockSize, self::$blockSize);
// We finally extract the ciphertext
$cipherText = substr($data, self::$blockSize * 2);
// Generate Key
$key = hash_pbkdf2('sha1', $secret, $salt, self::$iterations, self::$keySize, true);
// Check https://www.php.net/manual/en/function.openssl-decrypt.php
return openssl_decrypt($cipherText, self::$encryptionMethod, $key, OPENSSL_RAW_DATA, $iv);
}
}
The generateBase64Key or generateKey methods of the PBKDF2 package expect a string for the salt. In the implementation of these methods, the salt is UTF8 encoded.
Typically, a salt is randomly generated and therefore contains byte sequences that are incompatible with the UTF8 encoding. It is not known how the salt used here was generated. However, it contains (like a randomly generated salt) byte sequences that are incompatible with the UTF8 encoding. For this reason the PBKDF2 package applied is unsuitable for key derivation in this case. In my opinion, the choice of the string type for a salt is a poor design.
The cryptography package, on the other hand, provides a Pbkdf2 implementation that processes the salt as a Uint8List and is thus suitable. This library also supports AES/CBC, so it makes sense to use this library for the decryption as well.
The following implementation decrypts the posted ciphertext:
var encryptedResopnse = 'dBluiiVaHxhRcWJPaEip9kCGXDwufk3mFp8Xe9ioh9UKu6xL+CHUZrKvuf3xI7P1vFpvyyJ2Vz2Q3ieLEuRHk7NOinZU82FNdE3SOc9D2JTUFkif5ye3rVfQ7O39DpBnV41CduEP0OsASA8cr/RChqhulVHsaw6oUP0mg79M3Jlnpbab0EqlWRQx3k85rcajmov4cYLmsja++p2Lyw/BgOTKDf/yw3NWiK73Ot4P3C6urUiFNUCQTaOHCas1Sa8Wl0udQo1viyApuCE9+Ll1SGnUu26uNy5RR55IFLVnAHuIOBDePjdAw3DapAtLFnSd+FrVjYcUuevMMliSy3PHiZU66qdyx8YSn13tYH6KGFxC/kvPsi5dLGorQ1TdNR5fxZGRPNQXEEIwWYSiF8LA0AJzVqpRoXs9PkEseCUnH1Sj5sBQgXQc0RA8vHWf3n2X/cABLEWaRHHlBlZjqjJXl0uKSgAWC3JoelABGSuSCvL3GJhn9SuSV6+jCOftb6UCmw7LzalKB7UNIQPJ1vMtKl3+38RKDwp7a4xpdlln+IPp+R2aGuobuhk9ySSJYN3GCn7MoC/uaCAR0aEYsIHP1BQ+UgOPOsQFZEVdKMrFLJsJ3HtQ1fQxqpPQ13TClWCOyZu+w+1q4W+8CBJuI4l4Em+91aMT4xm7FWB/RhmUN8hfsHk7EATW8CkRGF4zFGKKdeN9zzGM0ViZYv30PARg8W2SJRKoZkaMOgZXtE/8D9fWzrmNDdHBCbMt0yrGycBbn8/b3JLQkcqxzY6VnWrBR1VJ66OB1mH5i6ejDrkxLx5VvkdKf3fcoKEZ/FptZK4zUwXgHJIF/YLChsYUj2mX9Ox18ZZi9vBG9L5vONc0GuQ31FzjwG77yGrJrS4mVi76uaifu7Thd6TiYXuu7OaFBl9+lPMvfHf+wWRqLQbgDoVtOXvND5e4LncWPHZbEjHGwO9I/MnVjMnH6nSbKER63Na8XBUIwsSlJwrswa3fLNInJA1/qGBb9nrVNzKLRfvku1UPvavDP1WxsTEzg0gH8Ui6KzBoBOd9IK/7ZtmSmSug5Ig8GAZ0R/kR7DnSs4ekxKxmcCJ95YVyf9fx0Vlw2oB9iOoUaHM3OITeldfMtoM=';
var secret = 'abcd123';
var decrypt = extractPayload(encryptedResopnse, secret);
print(decrypt);
with
import 'dart:convert' as ConvertPack;
import 'package:cryptography/cryptography.dart' as CryptographyPack;
...
String extractPayload(String encryptedResopnse, String secret) {
if (encryptedResopnse == null) {
return '';
}
// Separate data
// Note: Authentication not considered (separated: size = 1; see ciphertext and PHP code (hmac derived but unused))
var separated = encryptedResopnse.split(':');
var data = ConvertPack.base64Decode(separated[0].trim());
var iv = data.sublist(0, 16);
var salt = data.sublist(16, 32);
var cipherText = data.sublist(32);
// Derive key
var generator = CryptographyPack.Pbkdf2(
macAlgorithm: CryptographyPack.Hmac(CryptographyPack.sha1),
iterations: 2048,
bits: 256,
);
var hash = generator.deriveBitsSync(
ConvertPack.utf8.encode(secret),
nonce: CryptographyPack.Nonce(salt)
);
// Decrypt
var decrypted = CryptographyPack.aesCbc.decryptSync(
cipherText,
secretKey: CryptographyPack.SecretKey(hash),
nonce: CryptographyPack.Nonce(iv));
var plaintext = ConvertPack.utf8.decode(decrypted);
return plaintext;
}
and returns as result:
{"nofollow":false,"id":"2226521","title":"When You Say Nothing At All","album":"Ronan","albumID":"237798","artist":"Ronan Keating","artistID":"52715","track":"6","year":"1999","duration":"258.00","coverArt":"323816","ArtistArt":1002340723,"allowoffline":1,"genre":"Pop","AlbumArt":"323816","keywords":["When You Say Nothing At All","Ronan Keating","Ronan"],"languageid":2,"bitrates":"24,256","hexcolor":"#b43931","cleardetails":1,"bitrate":64,"size":"2108905","releasedate":"1999-01-01","explicit":"0","extras":"eyJyZXF1ZXN0dHlwZWlkIjo...","saveprogress":0,"lyrics":"true","is_podcast":0,"is_original":1,"location":"https:\\\/\\\/some audio file\u2019s URL","debugurl":"http:\\\/\\\/some URL","debugurldata":"http:\\\/\\\/some URL","hash":"b1229af8b0078e0b9ec9e203e3b32b7c","plays":"593963","likes":"13705"}
The cryptography package must be referenced in the pubspec.yaml in the dependencies section, here:
cryptography: ^1.4.1

Javascript AES with CryptoJS does not completely decrypt

All information i got are encrypted data (AES) and a key. The data must be a URL. I 've tried so many code-snippets (from stackoverflow) and found one snippets that worked for me partially.
// Decode the base64 data so we can separate iv and crypt text.
var rawData = atob(data);
var iv = btoa(rawData.substring(0,16));
var crypttext = btoa(rawData.substring(16));
// Decrypt...
var plaintextArray = CryptoJS.AES.decrypt(
{
ciphertext: CryptoJS.enc.Base64.parse(crypttext),
salt: ""
},
CryptoJS.enc.Hex.parse(key),
{ iv: CryptoJS.enc.Base64.parse(iv) }
);
// Convert hex string to ASCII.
function hex2a(hex) {
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
console.log(hex2a(plaintextArray.toString()));
The URL must be
http://test-example.com/hjhdsdfuisd
but the output is only
-example.com/hjhdsdfuisd.
I changed
var crypttext = btoa(rawData.substring(16));
to
var crypttext = btoa(rawData);
and got
­ô#XÍäÜ7±H4-example.com/hjhdsdfuisd.
What is my mistake?