How to do encryption like android's "PBEWithMD5AndDES" in flutter dart? - dart

I'm trying to recreate an existing mobile apps into flutter but struggling in the "PBEWithMD5AndDES" encryption on android which I can't seem to find similar way in dart.
This is so far what I've tried to achieve the same using Flutter_Des.dart, Password_Hash.dart and Crypto.dart library but still can't get the same output.
encryptPassword(String keyStr, String passwordStr) async {
if (keyStr.length == 0 || passwordStr.length == 0) {
return "";
}
var generator = new PBKDF2(hashAlgorithm: md5);
String saltStr = generateSaltBase64String();
var hash = generator.generateBase64Key(keyStr, saltStr, round, keyLength);
var encryptBase64 = await FlutterDes.encryptToBase64(passwordStr, hash.toString());
return encryptBase64;
}
Below is what I have currently on Android.
KeySpec keySpec = new PBEKeySpec(str.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
ecipher = Cipher.getInstance("PBEWithMD5AndDES");
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
byte[] utf8 = password.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
enc = Base64.encode(enc, Base64.DEFAULT);
return new String(enc);
I'm expecting the same output as android so my backend able to decrypt it.

PBEWithMD5AndDES uses PBKDF1 to generate the key material (not PBKDF2). This gives you 128 bits of key material that you then use as two 64 bit halves as the key and the IV for DES.
Derive the key and IV as follows - I've plugged in some arbitrary values for iteration, password and salt and confirmed against JCrypto.
int iterations = 31;
List<int> salt = [0x21, 0x21, 0xf0, 0x55, 0xc3, 0x9f, 0x5a, 0x75];
List<int> password = utf8.encode('test');
List<int> saltedKey = password + salt;
Digest d = md5.convert(saltedKey);
for (int i = 1; i < iterations; i++) {
d = md5.convert(d.bytes);
}
print(d);
List<int> key = d.bytes.sublist(0, 8);
List<int> iv = d.bytes.sublist(8, 16);
print(key);
print(iv);
I can't find a Dart implementation of DES which takes a key and IV as bytes. triple_des wants them as strings - i.e. it's dumbed down. Pointy castle doesn't do DES. FlutterDes also seems to want strings. You might be able to modify triple_des to take binary keys and IVs. Or use a different cipher.

Solved by using flutter's methodchannel and call platform specific code to do the encryption and its working now. Thanks

Related

Obtain hex string from the ECPrivateKey and ECPublicKey objects

I'm trying to use pointy castle to generate a public and private keypair using the secp256k1 curve. I think i have successfully created an AsymmetricKeyPair composed of an ECPrivateKey and ECPublicKey but i can't obtain their corresponding hex strings (something like this:
private:
ee792658c8eb1f8c3d2010ee6bc2ea328bb584fbecbfb17cf0f9103d122a8716,
public:
041b3f87beb2559aa3ca1c1d9ebb9447e4842d21cf0c70db103acc0db27ea8c27536fc2b1405b8a16a460ca089b01de8c556825927b4890b7236e357787f3e6d54).
When i try to print the keys, all i get is "Instance of 'ECPrivateKey'" and "Instance of 'ECPublicKey'" whether i use .toString() or not.
I have been looking around everywhere for a way to do this but i can't find one, is it even possible?
Here's my code:
SecureRandom secureRandom = new SecureRandom("Fortuna");
var random = new Random.secure();
List<int> seeds = [];
for (int i = 0; i < 32; i++) {
seeds.add(random.nextInt(255));
}
secureRandom.seed(new KeyParameter(new Uint8List.fromList(seeds)));
var domainParams = new ECDomainParameters("secp256k1");
var ecParams = new ECKeyGeneratorParameters(domainParams);
var params = new ParametersWithRandom<ECKeyGeneratorParameters>(
ecParams, secureRandom);
var keyGenerator = new ECKeyGenerator();
keyGenerator.init(params);
AsymmetricKeyPair keypair = keyGenerator.generateKeyPair();
ECPrivateKey privateKey = keypair.privateKey;
ECPublicKey publicKey = keypair.publicKey;
print(privateKey);
print(privateKey.toString());
print(publicKey);
print(publicKey.toString());
The private key and public point are member variables of their respective keys:
ECPrivateKey privateKey = keypair.privateKey;
ECPublicKey publicKey = keypair.publicKey;
// in decimal
print(privateKey.d);
print(publicKey.Q.x);
print(publicKey.Q.y);
// in hex
print(privateKey.d.toRadixString(16));
print(publicKey.Q.x.toBigInteger().toRadixString(16));
print(publicKey.Q.y.toBigInteger().toRadixString(16));

Writing a native messaging host in GJS

I'm trying to write a native messaging host for a chrome/firefox extension in GJS (since it will rely on code already written in GJS) but encountering some hurdles. I'm using chrome-gnome-shell as a rough template since it also uses GLib/Gio instrospection and GApplication, but it has the advantage of python struct that I don't have.
Quickly, native messaging hosts exchange messages through stdin/stdout which are an Int32 (4-bytes) length following by a string of utf-8 encoded JSON.
chrome-gnome-shell uses GLib.IOChannel with set_encoding('utf-8') and struct to handle int32 bytes. I've had trouble using that class in GJS and don't have struct so have been trying Gio.UnixInputStream wrapped in Gio.DataInputStream (and output counterparts), with put_int32()/read_int32() and put_string()/read_string().
Apparently I'm mightily confused about what I'm doing. If I call Gio.DataInputStream.read_int32() it returns a number 369098752, so I'm guessing the int32 is not being converted to a regular Number. If I call Gio.DataInputStream.read_bytes(4, null).unref_to_array() to get a ByteArray; ByteArray.toString() returns '\u0016' while ByteArray[0] returns '22' which appears to be the actual length.
Some pointers on reading/writing int32's to a datastream and would be much appreciated.
chrome-gnome-shell references:
on_input()
send_message()
I don't know if this is the best way to solve this, but here's what I came up with.
Two functions using the ByteArray import (modified from somewhere on SO):
const ByteArray = imports.byteArray;
function fromInt32 (byteArray) {
var value = 0;
for (var i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
}
return value;
};
function toInt32 (num) {
var byteArray = [0, 0, 0, 0];
for (var index_ = 0; index_ < byteArray.length; index_++) {
var byte = num & 0xff;
byteArray [index_] = byte;
num = (num - byte) / 256 ;
}
return ByteArray.fromArray(byteArray);
};
For receiving/sending:
const Gio = imports.gi.Gio;
// Receiving
let stdin = new Gio.DataInputStream({
base_stream: new Gio.UnixInputStream({ fd: 0 })
});
let int32 = stdin.read_bytes(4, null).toArray();
let length = fromInt32(int32);
let data = stdin.read_bytes(length, null).toArray().toString();
let message = JSON.parse(data);
// Sending
let stdout = new Gio.DataOutputStream({
base_stream: new Gio.UnixOutputStream({ fd: 1 })
});
let data = JSON.stringify(message);
let int32 = toInt32(data.length);
stdout.write(int32, null);
stdout.put_string(data, null);
Of course, you should wrap these in try-catch as appropriate and you'll probably want to connect a source to the input (you can use the Gio.UnixInputStream):
let source = stdin.base_stream.create_source(null);
source.set_callback(onReceiveFunc);
source.attach(null);
You may be able to use Gio.DataOutputStream.put_int32() and Gio.DataInputStream.read_int32() the same way as you use read_bytes() and put_string().

Writing a string to disk without any character conversion in Groovy

I have a String object, now because it comes a diff of a folder containing different file types, not everything in it is encoded in the same character set.
The correct codes are in the string, but whenever I try to access the string, groovy tries to be helpful and decode the string, which messes things up.
Now the following seems to do what I need
String decoded_diff = "String that contains codes from different character encodings"
patch_file_name = 'changes.patch'
patch_file = new File(pwd(), patch_file_name)
patch_file.delete()
max_block_size = 1024 * 1024
char[] char_buffer = new char[max_block_size]
block_start = 0
patch_length = decoded_diff.length()
while (true) {
block_size = Math.min(patch_length - block_start, max_block_size)
decoded_diff.getChars(block_start, block_start + block_size, char_buffer, 0)
block_start += block_size
byte[] byte_buffer = new byte[block_size]
for (int i = 0; i < block_size; i++) {
byte_buffer[i] = (int) char_buffer[i]
}
patch_file.append(byte_buffer)
if (block_start == patch_length) break
}
However, it is sloooow
Is there a faster way to achieve the same thing? The final patch file must be identical to the original diff to work. Unfortunately I can't send the file itself (jenkins currently doesn't support file parameters in pipeline jobs) so I have to escape it and send it as part of a json parameter list, hence this painful rigmarole on the receiving end.
Why not:
String decoded_diff = "String that contains codes from different character encodings"
patch_file_name = 'changes.patch'
patch_file = new File(pwd(), patch_file_name)
patch_file.delete()
patchFile.withOutputStream { os ->
os << decoded_diff.bytes
}

RSA encryption between Swift and C#

I need to build the Apple client part to an existing server that is written in .Net/C#. The client should run on OS X and iOS. Part of the communication is done using encrypted data, the C# source being something like
string privateKey = "xyz…=" // Base64 encoded
string publicKey = "abc…=" // Base64 encoded
byte[] decrypt(byte[] encryptedBytes)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 /* PROV_RSA_FULL */ };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(privateKey));
return rsaProvider.Decrypt(encryptedBytes, false);
}
This looks quite simple, but I cannot find a way to implement the encrypt counterpart in Swift.
The publicKey data consists solely of Modulus and Exponent numbers. I can extract the Modulus number from the public key with rsaProvider.ExportParameters(false).Modulus, the Exponent being [1, 0, 1] as usual.
How can I use the Modulus number (or the publicKey string constant itself) in my Swift application on the OS X / iOS client side, and how do I encrypt a plaintext there that can be decrypted on the C# server side?
I understand that Apple is not very fond of introducing cryptographic keys in such a low-level fashion, but there seems to be a possibility to import such a key into the keychain and then use it for encryption.
I have the building blocks (SecItem…(), SecKeyEncrypt(), etc.) but I cannot get it up and running.
Something like this should work on iOS.
For OS X, you need a slightly different approach (SecItemImport instead of SecItemAdd).
import UIKit
import Security
let publicKey = "MIIBCgKCAQEAxWp6GqUOG3xuMhaE0Eeb0eOqbPHE2lRQ53qg2A1rInWdBTVtQaU82Yurv6rFoz++jswiHf3VBy3plhalF+1CTruuzSqVUjpeWTGFppoIym8andVtGLP5mN56Ks7z8VxwQ4MvmM5lGqw3YX6NWVNirWTGdJsqiplmhkAZXFAY43ivwTFSbQ4Uhx7SA0PK537V6je5MJ9edaWpKc1HoGH/bZG9/qrunv2Wam0w9qb8/TOsNvxdgBFs9WZaU0amkNb4h94y9ZrJKYsRGTngDAZ/uA+WK5ZM+Dz3GelsDUErvlUlswLyhQKYPPGn+QlVbMF4drUZ6piZWPmvpY2a/iyRcwIDAQAB"
let keyData = NSData(base64EncodedString: publicKey, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
var dictionary: [NSString: AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrApplicationTag: "mypubkeyappspecifictag",
kSecValueData: keyData!,
kSecReturnRef: true
];
var err = SecItemAdd(dictionary, nil);
if ((err != noErr) && (err != errSecDuplicateItem)) {
print("error loading public key");
}
var keyRef: AnyObject?;
err = SecItemCopyMatching(dictionary, &keyRef);
if (err == noErr) {
if let keyRef = keyRef as! SecKeyRef? {
let plaintext = "12345";
let plaintextLen = plaintext.lengthOfBytesUsingEncoding(NSUTF8StringEncoding);
let plaintextBytes = [UInt8](plaintext.utf8);
var encryptedLen: Int = SecKeyGetBlockSize(keyRef);
var encryptedBytes = [UInt8](count: encryptedLen, repeatedValue: 0);
err = SecKeyEncrypt(keyRef, SecPadding.PKCS1, plaintextBytes, plaintextLen, &encryptedBytes, &encryptedLen);
if (err != noErr) {
print(encryptedBytes);
}
}
}
SecItemDelete(dictionary);
Please note that public key for iOS should be stripped of ASN1 preamble, as specified here.
Finally, I found the right combination. Alex Skalozub's answer was a great help in this process.
Here's my process step by step:
It starts with the public key string that was given on the server side. This had been generated previously this way: (C# .Net)
CspParameters cspParams = new CspParameters { ProviderType = 1 /* PROV_RSA_FULL */ };
// generate key pair with given size
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(4096, cspParams);
string publicKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(false));
string privateKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(true));
These keys are stored internally as string constants and are then, after extracting them from their base64 representation, imported when the server is initializing:
CspParameters cspParams = new CspParameters { ProviderType = 1 /* PROV_RSA_FULL */ };
// no key generation this time:
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(publicKey));
Since these "CSP Blobs" are a proprietary Microsoft Cryptographic API structure, I had to use them and extract the low-level RSA numbers (n and e for the public key; d for the private key was not really needed here): (C# .Net)
RSAParameters pub = rsaProvider.ExportParameters(false);
string n = Convert.ToBase64String(pub.Modulus);
string e = Convert.ToBase64String(pub.Exponent);
RSAParameters priv = rsaProvider.ExportParameters(true);
string d = Convert.ToBase64String(priv.D);
Next step is building an Apple-compatible (i.e. non standard conforming) key string from the numbers. I used Python with the PyCrypto package:
import base64
from Crypto.Util import asn1
def b64ToNum(b64str):
byteStr = base64.b64decode(b64str)
num = 0L
for digit in byteStr:
num = num * 256 + ord(digit)
return num
n_b64 = "..." # copied from C# output
e_b64 = "..." # copied from C# output
n = b64ToNum(n_b64)
e = b64ToNum(e_b64)
seq = asn1.DerSequence()
seq[:] = [ n, e ] ## Standard would be [ 0, n, e ] !!!
print s.encode("base64").replace("\n", "")
This produces a base64-encoded public key string that can be used for insertion in the iOS keychain, as shown in Alex' code (SecItemAdd, SecItemCopyMatching).
I also verified that the C# code can successfully decrypt data I encrypt on the iOS side.

Generate base64 url-encoded X.509 format 2048-bit RSA public key with Swift?

Working in Apple Swift for iOS. I have to generate this for the backend as it's a secure app.
I'm new to security and certificates and have been searching for a day now with no results.
How can I generate base64 url-encoded X.509 format 2048-bit RSA public key with swift?
Any help is highly appreciated.
There's a library for handling public-private key pairs in Swift that I recently created called Heimdall, which allows you to easily export the X.509 formatted Base64 string of the public key.
To comply with SO rules, I will also include the implementation in this answer (so that it is self-explanatory)
public func X509PublicKey() -> NSString? {
// Fetch the key, so that key = NSData of the public key
let result = NSMutableData()
let encodingLength: Int = {
if key.length + 1 < 128 {
return 1
} else {
return ((key.length + 1) / 256) + 2
}
}()
let OID: [CUnsignedChar] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00]
var builder: [CUnsignedChar] = []
// ASN.1 SEQUENCE
builder.append(0x30)
// Overall size, made of OID + bitstring encoding + actual key
let size = OID.count + 2 + encodingLength + key.length
let encodedSize = encodeLength(size)
builder.extend(encodedSize)
result.appendBytes(builder, length: builder.count)
result.appendBytes(OID, length: OID.count)
builder.removeAll(keepCapacity: false)
builder.append(0x03)
builder.extend(encodeLength(key.length + 1))
builder.append(0x00)
result.appendBytes(builder, length: builder.count)
// Actual key bytes
result.appendData(key)
// Convert to Base64 and make safe for URLs
var string = result.base64EncodedStringWithOptions(.allZeros)
string = string.stringByReplacingOccurrencesOfString("/", withString: "_")
string = string.stringByReplacingOccurrencesOfString("+", withString: "-")
return string
}
public func encodeLength(length: Int) -> [CUnsignedChar] {
if length < 128 {
return [CUnsignedChar(length)];
}
var i = (length / 256) + 1
var len = length
var result: [CUnsignedChar] = [CUnsignedChar(i + 0x80)]
for (var j = 0; j < i; j++) {
result.insert(CUnsignedChar(len & 0xFF), atIndex: 1)
len = len >> 8
}
return result
}
I have removed the data fetching code, refer to either source of Heimdall or Jeff Hay's answer
If the public key is already in your keychain, you can look up the public key and return the data as base64 with something similar to the following:
// Create dictionary to specify attributes for the key we're
// searching for. Swift will automatically bridge native values
// to to right types for the SecItemCopyMatching() call.
var queryAttrs = [NSString:AnyObject]()
queryAttrs[kSecClass] = kSecClassKey
queryAttrs[kSecAttrApplicationTag] = publicKeyTag
queryAttrs[kSecAttrKeyType] = kSecAttrKeyTypeRSA
queryAttrs[kSecReturnData] = true
var publicKeyBits = Unmanaged<AnyObject>?()
SecItemCopyMatching(queryAttrs, &publicKeyBits)
// Work around a compiler bug with Unmanaged<AnyObject> types
// the following two lines should simply be
// let publicKeyData : NSData = publicKeyRef!.takeRetainedValue() as NSData
let opaqueBits = publicKeyBits?.toOpaque()
let publicKeyData = Unmanaged<NSData>.fromOpaque(opaqueBits).takeUnretainedValue()
let publicKeyBase64 = publicKeyData.base64EncodedData(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
If you need to generate the keypair and store it in the keychain, use something along these lines:
// Create dictionaries to specify key attributes. Swift will
// automatically bridge native values to to right types for the
// SecKeyGeneratePair() call.
var pairAttrs = [NSString:AnyObject]()
var privateAttrs = [NSString:AnyObject]()
var publicAttrs = [NSString:AnyObject]()
privateAttrs[kSecAttrIsPermanent] = true
privateAttrs[kSecAttrApplicationTag] = privateKeyTag
publicAttrs[kSecAttrIsPermanent] = true
publicAttrs[kSecAttrApplicationTag] = publicKeyTag
pairAttrs[kSecAttrKeyType] = kSecAttrKeyTypeRSA
pairAttrs[kSecAttrKeySizeInBits] = 2048
pairAttrs[(kSecPrivateKeyAttrs.takeUnretainedValue() as! String)] = privateAttrs
pairAttrs[(kSecPublicKeyAttrs.takeUnretainedValue() as! String)] = publicAttrs
var publicKeyPtr = Unmanaged<SecKey>?()
var privateKeyPtr = Unmanaged<SecKey>?()
let status = SecKeyGeneratePair(pairAttrs, &publicKeyPtr, &privateKeyPtr)
Note: publicKeyTag and privateKeyTag are strings used to identify the key in the keystore. Apple recommends reverse-dns notation (com.company.key.xxx), but as long as they are unique, all should be good.
Similar question with answer: Generate key pair on iphone and print to log as NSString
Although the answer there is in Objective-C, Apple reference shows that the functions (especially the most important one, SecKeyGeneratePair) can also be called directly from Swift (as long as you can do the type conversions from all those UnsafeMutablePointers etc).

Resources