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));
Related
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
I have added pointycastle and generated a keypair, encrypting the trial "Hello World" string. From this, I want to get the values of the Private and Public Key. Is there anywhere they are stored, because whenever I try to print the values of keyPair.privateKey, it returns Instance of 'RSAPrivateKey.
Here is the code I used
var keyParams = new RSAKeyGeneratorParameters(new BigInt.from(65537), 2048, 5);
var secureRandom = new FortunaRandom();
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 rngParams = new ParametersWithRandom(keyParams, secureRandom);
var k = new RSAKeyGenerator();
k.init(rngParams);
var keyPair = k.generateKeyPair();
var cipher = new RSAEngine()..init( true, new PublicKeyParameter<RSAPublicKey>(keyPair.publicKey));
print("pubkey: ${keyPair.publicKey.toString()}");
var cipherText = cipher.process(new Uint8List.fromList("Hello World".codeUnits));
print("Encrypted: ${new String.fromCharCodes(cipherText)}");
cipher.init( false, new PrivateKeyParameter<RSAPrivateKey>(keyPair.privateKey));
//cipher.init( false, new PrivateKeyParameter(keyPair.privateKey) )
var decrypted = cipher.process(cipherText);
print("Decrypted: ${new String.fromCharCodes(decrypted)}");
Make sure to import package:pointycastle/asymmetric/api.dart, then use:
var k = RSAKeyGenerator()..init(rngParams);
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = k.generateKeyPair();
RSAPrivateKey privateKey = keyPair.privateKey;
RSAPublicKey publicKey = keyPair.publicKey;
print(privateKey.d); // prints private exponent
print(publicKey.n); // prints modulus
Recreate from the individual parts:
RSAPrivateKey foo = RSAPrivateKey(
privateKey.n,
privateKey.d,
privateKey.p,
privateKey.q,
);
RSAPublicKey bar = RSAPublicKey(publicKey.n, publicKey.e);
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.
How do I base64 encode a string in cloud code? The value is for a HTTP Basic Auth.
I have tried the following two approaches and I had no success.
var string = 'AQXTTPmj-boT_yDEPQXg9ezIOIM7O:EMx6RLr8jF3S6YYo-X4bZ';
var buffer1 = new Buffer(string, 'base64');
var b3 = buffer1.toString('base64');
console.log(b3);
var string = 'AQXTTPmj-boT_yDEPQXg9ezIOIM7O:EMx6RLr8jF3S6YYo-X4bZ';
var encodeString = Base64.encode(string);
console.log(encodeString);
You send your string to the Buffer constructor and use toString method to convert it to base64 like this:
var string = 'AQXTTPmj-boT_yDEPQXg9ezIOIM7O:EMx6RLr8jF3S6YYo-X4bZ';
var buffer1 = new Buffer(string);
var b3 = buffer1.toString('base64');
console.log(b3);
Also make sure you put var Buffer = require('buffer').Buffer; on top of your main.js file.
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).