How to store long public key string in Dart/Flutter? - flutter

I am testing out some PGP encryption in Flutter using the openpgp package. I'm trying to encrypt using a public key, but I'm not sure how to store such a long string.
Here is their example:
var result = await OpenPGP.encrypt("text","[publicKey here]");
Here is a example public key, but I can't store it properly. Even using r"key" I get many errors.

I found in a example document for simple_rsa this is how they store the key:
final PUBLIC_KEY =
"MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBuAGGBgg9nuf6D2c5AIHc8" +
"vZ6KoVwd0imeFVYbpMdgv4yYi5obtB/VYqLryLsucZLFeko+q1fi871ZzGjFtYXY" +
"9Hh1Q5e10E5hwN1Tx6nIlIztrh5S9uV4uzAR47k2nng7hh6vuZ33kak2hY940RSL" +
"H5l9E5cKoUXuQNtrIKTS4kPZ5IOUSxZ5xfWBXWoldhe+Nk7VIxxL97Tk0BjM0fJ3" +
"8rBwv3++eAZxwZoLNmHx9wF92XKG+26I+gVGKKagyToU/xEjIqlpuZ90zesYdjV+" +
"u0iQjowgbzt3ASOnvJSpJu/oJ6XrWR3egPoTSx+HyX1dKv9+q7uLl6pXqGVVNs+/" +
"AgMBAAE=";

Related

Dart / Flutter : How Do I Sign a String Using an ES 256 Algorithm and Private Key

Since Flutter doesn't support any map APIs across all platforms (mobile and desktop), I'm trying to fetch map snapshots with Apple's Web Snapshots API. This involves constructing a URL with various options then signing the URL. I append the signature to the end of my request URL so Apple can verify that it's from me.
Apple's instructions state:
To generate a signature, sign the string with your private key using a ES256 algorithm (also known as ECDSA using P-256 curve and SHA-256 hash algorithm). The signature must be Base64 URL-encoded.
I don't need to decrypt anything, I just need to sign the string and add it to the end of my request URL. So I don't think I need anything beyond the crypto library included with Flutter.
Here's what I've tried:
import 'package:crypto/crypto.dart';
//Private Key
var key = utf8.encode('''
-----BEGIN PRIVATE KEY-----
abcdef...
-----END PRIVATE KEY-----
''');
var bytes = utf8.encode('My URL String to Sign...');
var hmacSha256 = Hmac(sha256, key);
var sig = hmacSha256.convert(bytes);
var signature = base64UrlEncode(sig.bytes);
I get an unintelligible string as signature and add it to my request URL, but I still get a 401 Not Authorized error, so my signature must be incorrect.
How can I properly sign my URL string with my private key?
Using pointycastle, you need a suitable random number generator instance and a signer initialized with the relevant digest. Then just call generateSignature. That only gets you the r and s values which you need to encode.
Here's an example:
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:pointycastle/asn1.dart';
import 'package:pointycastle/export.dart';
// the private key
ECPrivateKey? privateKey;
// some bytes to sign
final bytes = Uint8List(0);
// a suitable random number generator - create it just once and reuse
final rand = Random.secure();
final fortunaPrng = FortunaRandom()
..seed(KeyParameter(Uint8List.fromList(List<int>.generate(
32,
(_) => rand.nextInt(256),
))));
// the ECDSA signer using SHA-256
final signer = ECDSASigner(SHA256Digest())
..init(
true,
ParametersWithRandom(
PrivateKeyParameter(privateKey!),
fortunaPrng,
),
);
// sign the bytes
final ecSignature = signer.generateSignature(bytes) as ECSignature;
// encode the two signature values in a common format
// hopefully this is what the server expects
final encoded = ASN1Sequence(elements: [
ASN1Integer(ecSignature.r),
ASN1Integer(ecSignature.s),
]).encode();
// and finally base 64 encode it
final signature = base64UrlEncode(encoded);
A huge thanks to Richard Heap for providing the solution. I just wanted to post the final code I settled on for anyone running into this in the future. Only the basic_utils package is needed.
import 'package:basic_utils/basic_utils.dart';
import 'dart:typed_data';
final url = 'My URL string...';
//Convert the URL string to Uint8List
final urlBytes = utf8.encode(url) as Uint8List;
//Prep the private key
var key = '''
-----BEGIN PRIVATE KEY-----
abcdef...
-----END PRIVATE KEY-----
''');
ECPrivateKey privateKey = CryptoUtils.ecPrivateKeyFromPem(key);
//Sign the URL
ECSignature sig = CryptoUtils.ecSign(privateKey, urlBytes, algorithmName: 'SHA-256/ECDSA');
//Convert signature to Base64
final signature = CryptoUtils.ecSignatureToBase64(sig);
I just add that signature to the end of the URL string as required by Apple's API and it works great!

how to decrypt a base 64 string?

I'll explain my problem, I'm trying to encrypt a password, then save it locally so that I can go and retrieve it when necessary, decrypt it and assign it wherever I want.
In the encryption phase I do not get any problems in the sense that the encrypt method can easily return a string while in the decrypt method I have problems, because the return type seems to have to be of the Encrypt type.
By doing so it is impossible for me to go and get the string saved locally thanks to sharedPreferences and be able to decrypt it, I am going to give you the code below to better understand my problem:
class _State extends State<SettingsPage> {
static final key = encrypt.Key.fromLength(32);
static final iv = encrypt.IV.fromLength(16);
static final encrypter = encrypt.Encrypter(encrypt.AES(key));
static encryptAES(text) {
final encrypted = encrypter.encrypt(text, iv: iv);
return encrypted;
}
static decryptAES(text) {
print(text.base64);
String decrypted = encrypter.decrypt(text, iv: iv);
print(decrypted);
return decrypted;
}
SettingsPage.inputPassword = input[0];
// SettingsPage.inputPassword = tec.text;
encryptedText = encryptAES(SettingsPage.inputPassword).base64;
setState(() {
String encryptedText =
encryptAES(SettingsPage.inputPassword).base64;
print("PROVA ENCRYPTED TEXT " + encryptedText);
});
prefs.setString('savedPass', encryptedText.base64);
String decryptedText = decryptAES(encryptedText).base64;
print("PROVA TESTO DECRIPTATO " + decryptedText);
}
},
Everything proceeds as required until the password is saved, then I ask you how to decrypt a string in order to be able to assign the variable DecryptedText to the String variable correctly, since at this moment I am told:
Unhandled Exception: NoSuchMethodError: Class 'String' has no instance getter 'base64'.
This is because it would appear that the decrypted method can only return an Encrypt type.
The pub.dev API used is encrypt: ^5.0.1.
THANKS.
I'm not familiar with package:encrypt, but skimming over the documentation you should be using Encrypted.fromBase64 to construct an Encrypted object to pass to Encrypter.decrypt:
static String decryptAES(String base64Text) {
print(base64Text);
String decrypted = encrypter.decrypt(Encrypted.fromBase64(base64Text), iv: iv);
print(decrypted);
return decrypted;
}
Note that you also should be calling just decryptAES(...), not decryptAES(...).base64. (You want the original text back, not a base64-encoded version.)
encryptedTextBase64 = encryptAES(SettingsPage.inputPassword).base64;
...
String decryptedText = decryptAES(encryptedTextBase64);
I will point out that your code is very hard to follow (which is especially bad for security-related code) because:
Your functions do not declare argument types nor return types and therefore take and return dynamic types. This makes it hard to understand what arguments they expect and what they are expected to return.
You should name your variables to make it clear what is base64-encoded and what isn't. (I renamed the variables in the example above.)

Decrypt JWT Token in C#

Hello I'm trying to see if they're any JWT token library similar to JOSE-JWT that also works on a Linux machine during runtime.
This is what I currently have in code that decrypts a token and grabs what I need.
private IamTokenDecrypted DecryptToken(string idToken)
{
byte[] key = WebEncoders.Base64UrlDecode(_ssoEncryptionKeyInfo.JsonWebKey.K);
string json = Jose.JWT.Decode(idToken, key, JweAlgorithm.DIR, JweEncryption.A256GCM);
var result = Jose.JWT.Payload(json);
var iamTokenDecrypted = JsonConvert.DeserializeObject<IamTokenDecrypted>(result);
return iamTokenDecrypted;
}
I have a security key and and as you see it has some encryption in it

Postman RSA Encryption

I would like to utilize postman to test a REST API that requires one of the input fields to be encrypted with RSA encryption.
I see that postman provides the functionality through require('crypto-js') to encrypt using AES encryption, but I that library does not provide RSA encryption. How can I use post man to automate RSA encryption?
The flow would work like this:
Call a REST API that returns an RSA public key
Store the RSA public key in a variable
Utilize that public key to encrypt an value in the following request
before sending
I have created a little ¨library¨ to use cryptographic methods in Postman Pre-request and Tests script, RSA is totally supported, have a look to the tutorial here, is very easy to use.
https://joolfe.github.io/postman-util-lib/
Best Regards.
Here is an example of how to RSA encrypt using the 'RSAOAEP' alg:
// RSAOAEP signature example
const pubkey = '-----BEGIN PUBLIC KEY-----\n' +
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAstXEkU/agbNkQgh6a9DV\n' +
'C/WXGmNy8g+hdTOBhYUk5PfZCwTNt5SCYBLjIPhs2ZRrNuCN3PhwHRQPQOTsS6Nl\n' +
'Bzw+SjPVFBhPcbMHbJWnC87Q5ID/uAuwJjcUQXUTVspwIgfRmHvuuT7w7AYnCNvz\n' +
'B5TuPj2vVH8rij9BXkAHambaeGG7L10MPeUiVU6M0F/QKCJhEWAYGEt4NffSXETx\n' +
'zHSl8nyXxVJfnjxVhnZyZVXTIpLwvRy04hnkAoFexh7npRtnQdsLuIHtaJsm7gFY\n' +
'mxhr3Nxbh9p1pC7fHpJ+jMcxAAhA07WqYf6lOsxXHfPav1FEMX214YTsKTw68xqo\n' +
'DwIDAQAB\n' +
'-----END PUBLIC KEY-----\n'
const fileContent = 'My file content comes here...'
const keyObj = pmlib.rs.KEYUTIL.getKey(pubkey)
const encHex = pmlib.rs.KJUR.crypto.Cipher.encrypt(fileContent, keyObj, 'RSAOAEP')
console.log(encHex)
// will return the hexadecimal encoded, can be converted to many format ussing the library too
I dit it.
you need https://github.com/digitalbazaar/forge
and compile it, not from cdn, can not work
load from your script
1.load script
var server = postman.getEnvironmentVariable("server");
if (!postman.getEnvironmentVariable("forgeJS")) {
pm.sendRequest("http://" + server + "/res/forge.js", function(err, res) {
if (err) {
console.log(err);
} else {
postman.setEnvironmentVariable("forgeJS", res.text());
}
})
}
2.eval script and encrypt
var password = '123456';
var public_key = '-----BEGIN PUBLIC KEY-----\n' +
pm.environment.get("rsaKey") + '\n' +
'-----END PUBLIC KEY-----';
var jsscript = pm.environment.get("forgeJS");
eval(jsscript);
console.info(public_key)
var publicKey = forge.pki.publicKeyFromPem(public_key);
var encryptedText = forge.util.encode64(publicKey.encrypt("123456", 'RSA-OAEP', { // server Java private decrypt
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha1.create()
}
}));
postman.setEnvironmentVariable("password", encryptedText);

RSA encryption issue in C#

I have an api that returns me public key. Here is a public key sample,
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ9AMIIBCgKCAQEAoqB1N9kugk4UKYnbh0fcg3qYyYKP0m4B
MjWd05ReeAdj+7JRYDEKO6xthDdVSdRO1/2V+YtY8DnXWnxRaICwu8235s3imZCyqgYnomPWdY+F
K540oTz/zug+9wbrlzt/WQFUU4lPlQbzm/Gjw8XfaCozT0e3bnWQcD7rORCOyuJgwSGgREjTv1ss
pgEaKTMknii9vpGZLeAXwoeIYROhuT4IoIkPDhtY0/UZiCi6v7Ja2dmy53VlWIkcm3rcnSJdvpXr
OgiHvaNABHmeymNycNqd6WUaysBRheluQ86nq/2nZPW0gcvmYt5zbMMYX3yY/n2WtAKeNQBAEW1q
b0s6MwIDAQAB
Now I need to encode string a=1&b=2 using RSA algorithm,
var key = await GetPublicKey();
var keyXml = "<RSAKeyValue><Modulus>" + key + "</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
EncrptedValue = CryptUtils.Encrypt(keyXml, "amount=1&currency=aed", RsaKeyLengths.Bit1024);
I am using CryptUtils class at https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Common/CryptUtils.cs.
Now I am sending the encrypted value to another server but another server guy telling me that the encrypted value is not corect. What I am doing wrong?