Encrypt string using PCLCrypto - rsa

I have a RSA key which I got from a service provider. I just want to encrypt the string data with that RSA key by using the PCLCrypto library. I don't want to create the RSA key by using PCLCrypto. I only wanted to encrypt the data. (I am developing a PCL component in xamarin.)

Follow the documentation for AES encryption and modify it for RSA. Use AsymmetricAlgorithm.RsaPkcs1 as algorithm provider.
Below example is for AES.
byte[] keyMaterial;
byte[] data;
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
// The IV may be null, but supplying a random IV increases security.
// The IV is not a secret like the key is.
// You can transmit the IV (w/o encryption) alongside the ciphertext.
var iv = WinRTCrypto.CryptographicBuffer.GenerateRandom(provider.BlockLength);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key, data, iv);
// When decrypting, use the same IV that was passed to encrypt.
byte[] plainText = WinRTCrypto.CryptographicEngine.Decrypt(key, cipherText, iv);

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 do I decrpyt a message with AES when I have only the encrypted message and a key in flutter?

How do I decrypt a message when I have only the message and the key?
I know the key (as a string), and the encrypted message is returned from my friend's API (as a string). My friend uses CryptoJS to encrypt with AES. How do I decrypt that message? I think my friend uses the default settings for everything (in CryptoJS).
I'm trying it with encrypt in flutter. The thing is encrypter.decrypt() accepts the type Encrypted and iv while I have the encrypted message as a String. How do I convert it to Encrypted? Also, how do I obtain the iv?
Here's an example of the known information (both are String)
Encrypted message: U2FsdGVkX1851cYw0S6LX/xhUwdy0R/1AlNun5L9Ykc=
Key Example: myKey111
I'm currently out of ideas.
Here's what I have currently
String key = 'myKey111';
String keyB64 = base64.encode(utf8.encode(key));
final keyKey = encrypt.Key.fromBase64(keyB64);
String code = "U2FsdGVkX1851cYw0S6LX/xhUwdy0R/1AlNun5L9Ykc=";
List<int> list = code.codeUnits;
Uint8List bytes = Uint8List.fromList(list);
final _encrypted = encrypt.Encrypted(bytes);
print('KEY TEST: ${keyKey.base64}');
final _encrypter = encrypt.Encrypter(encrypt.AES(
keyKey,
mode: encrypt.AESMode.cbc,
padding: 'PKCS7',
));
final iv = encrypt.IV.fromUtf8('myKey111');
final _decrypted = _encrypter.decrypt(_encrypted, iv: iv);

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

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?

send RSA public key to iphone and use it to encrypt

I have a TCP socket server and I want to do the following w/o using SSL:
On server, make RSA key pair (I know how to do this using openssl's crypto library)
On server, send the public key to iphone and keep the private key.
On client(iphone), want to encrypt a message using the public key, using SecKeyEncrypt.
On server, decrypt the message.
The message is short enough so that the PKCS1 padded result fits into 128 bytes.
I don't know how to do 2~4. Anyone knows?
This should do what you're asking - it encrypts data with the server's public key. It's not subject to MITM attacks, unless the attacker has a copy of your private key and its password (communicating via non-SSL, however, still is, but the data you encrypt with the server's legit public key will be nearly impossible to decrypt).
I cobbled this together from Apple's docs, this site, the Apple developer forums and probably elsewhere. So thanks to everyone I cribbed code from! This code assumes several things:
You've already generated your RSA key pairs (I'm using a 4096-bit key and it seems speedy enough) and, using the private key, created a DER-encoded certificate called "cert.cer" that you put in your resource bundle of your app (obviously, you can also download the cert from your server, but then you're open to MITM attacks again). By default, OpenSSL generates a PEM encoded cert, so you have to convert it with "openssl x509 -in cert.pem -inform PEM -out cert.cer -outform DER". iOS will barf on PEM. The reason I use a cert is it's actually easier to work with, and is supported in iOS. Using just the public key isn't (though it can be done).
You've added Security.framework to your project and you #import <Security/Security.h>.
/*
Returns an NSData of the encrypted text, or nil if encryption was unsuccessful.
Takes the X.509 certificate as NSData (from dataWithContentsOfFile:, for example)
*/
+(NSData *)encryptString:(NSString *)plainText withX509Certificate:(NSData *)certificate {
SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificate);
SecPolicyRef policy = SecPolicyCreateBasicX509();
SecTrustRef trust;
OSStatus status = SecTrustCreateWithCertificates(cert, policy, &trust);
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(trust, &trustResult);
}
SecKeyRef publicKey = SecTrustCopyPublicKey(trust);
const char *plain_text = [plainText UTF8String];
size_t blockSize = SecKeyGetBlockSize(publicKey);
NSMutableData *collectedCipherData = [NSMutableData data];
BOOL success = YES;
size_t cipherBufferSize = blockSize;
uint8_t *cipherBuffer = malloc(blockSize);
int i;
for (i = 0; i < strlen(plain_text); i += blockSize-11) {
int j;
for (j = 0; j < blockSize-11 && plain_text[i+j] != '\0'; ++j) {
cipherBuffer[j] = plain_text[i+j];
}
int result;
if ((result = SecKeyEncrypt(publicKey, kSecPaddingPKCS1, cipherBuffer, j, cipherBuffer, &cipherBufferSize)) == errSecSuccess) {
[collectedCipherData appendBytes:cipherBuffer length:cipherBufferSize];
} else {
success = NO;
break;
}
}
/* Free the Security Framework Five! */
CFRelease(cert);
CFRelease(policy);
CFRelease(trust);
CFRelease(publicKey);
free(cipherBuffer);
if (!success) {
return nil;
}
return [NSData dataWithData:collectedCipherData];
}
Well, I guess you would need to publish your public key to the outside world (the iPhone in your case). To do the best way is to publish a certificate conatining your public key, and the iPhone app can download it. Then the iPhone application can utilize the principle of PGP to encrypt the data with a symmetric algo (like AES) and encrypt the symmetric with the public key. The application in the server would receive the message, decrypt the symmetric key with its private key, and the then decrypt the encrypted data with the symmetric key thus obtained.
But as cobbal said, anyone can intercept the message in between the server and the iPhone and can change it, and the server would not know if its has 'actually' recieved the data from the iPHone, unless you sign it using an SSL certificate (i.e. encrypt the hash of the method with the private key of the iPhone).
My suggestion is, use availale third party application rather than doing it yourself, as they might be some falw in tghe implementation. PGP is a public available library, u can use.