Create SSH RSA key pair with PEM encoding using OpenSSL - objective-c

I am trying to generate OpenSSH key pairs on iOS. I now stuck how to create/extract a public ssh-RSA key from a PEM, equivalent to this:
ssh-keygen -y -f ~/.ssh/private
This is how I am creating the private key, which seems to create a valid key pair.
const int kBits = 1024;
const int kExp = 3;
int keylen;
int pub_len;
char *pem_key;
RSA *rsa = RSA_generate_key(kBits, kExp, 0, 0);
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
keylen = BIO_pending(bio);
pem_key = calloc(keylen+1, 1); /* Null-terminate */
BIO_read(bio, pem_key, keylen);
printf("%s", pem_key);
BIO_free_all(bio);
RSA_free(rsa);
free(pem_key);
I am new to cryptography and C, any hints or clues are much appreciated. Thanks in advance!

Related

Generate private/public pair key using ECC : elliptic curves

I working on little ECC crypto problem.
The goal is to write a program in C or bash, which will take as input a hash composed of 128 characters in hexadecimal
(Example: 8A9A35145C4EA5260DF9972C804FE2D3F9F3D7A2AC01A6BEB21C82BB30957B3952273AC9166B90C1207347A925780F84A1D2359E7AA05201C674D2B9746FCA07)
and which will generate from the input hash a private key and a public key of type Elliptic Curve and display the key pair generated.
Can someone clarify for me the problem. I can't understand why we need a hash(or any string) to generate a pair key, as I found In many online solution like this one ther's no need to give a hash. Maybe is it a parphase ? Maybe It's the curve key or somthing similar.
I think all we need is to do something like this for the private key:
openssl ecparam -genkey -noout -out myprivatekey.pem
and for the public key generation:
openssl -ec -in myprivatekey.pem -pubout -out mypublickey.pem
The question is : why we need an input a hash composed of 128 to generate our pair keys? Is it a passphrase for security reason? how made the trick with openssl ?
You could use a hash if you've got some kind of input binary value which you need to convert to a key.
You can use a hash as input for a private key. To convert it you should first convert it to a number and then perform a calculation modulo n on it, where n is the order of the ECC domain parameters. The resulting value can be called s Then you can calculate the public key out of it by performing s * G, i.e. point multiplication with the base point.
OpenSSL is not a low level crypto library, so you'd have to program it, possibly using the OpenSSL API and the BN (big number) library that comes with it. It is not that tricky, but if you're still talking about 128 characters instead of 64 bytes then you may have a lot of learning to do.
In fact this is my own code, you can improve it and edit the solution bellow:
// gcc -Wall ecdsapubkey.c -o ecdsapubkey -lcrypto
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
int main()
{
EC_KEY *eckey = NULL;
EC_POINT *pub_key = NULL;
const EC_GROUP *group = NULL;
BIGNUM *start;
BIGNUM *res;
BN_CTX *ctx;
start = BN_new();
ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
res = start;
BN_hex2bn(&res,"8A9A35145C4EA5260DF9972C804FE2D3F9F3D7A2AC01A6BEB21C82BB30957B3952273AC9166B90C1207347A925780F84A1D2359E7AA05201C674D2B9746FCA07");
eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
group = EC_KEY_get0_group(eckey);
pub_key = EC_POINT_new(group);
printf("private key : "); BN_print_fp(stdout, res); printf("\n");
EC_KEY_set_private_key(eckey, res);
/* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */
if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
printf("Error at EC_POINT_mul.\n");
EC_KEY_set_public_key(eckey, pub_key);
char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
char *c=cc;
int i;
printf("public key : ");
for (i=0; i<130; i++) // 1 byte 0x42, 32 bytes for X coordinate, 32 bytes for Y coordinate
{
printf("%c", *c++);
}
printf("\n");
BN_CTX_free(ctx);
free(cc);
return 0;
}

Extract public key from private key in pem format

How can I implement the effect of following command in Objective-C?
openssl rsa -in mykey.pem -pubout > mykey.pub
I'm able to generate a private key in pem format.
Here is the code I use to read the private key into a openssl RSA object.
BIO* bpPrivate = nil;
NSString *filePath = .....
const char *path = [filePath UTF8String];
bpPrivate = BIO_new_file(path, "r");
_rsa = PEM_read_bio_RSAPrivateKey(bpPrivate, NULL, 0, NULL);
I want to extract the public key from the private key.
In memory, there is no notion of ASN.1, DER, PEM or other encodings. A RSA key uses the same structure for both the public and private key. For a public key, some fields are not used. If you are interested in the fields, then visit PKCS #1 or RFC 3447.
So, given an RSA*, all you need to do is call PEM_write_bio_RSAPublicKey (even with a private key). You can also use PEM_write_RSAPublicKey (even with a private key). See pem(3) for all the read and write functions.
You can also accomplish it the long way by way of RSAPublicKey_dup. It will take a priavte key (i.e., a RSA*) and return a public key (i.e., a RSA*). But its kind of an unnecessary step for the most part. It might be useful to keep the key in memory, if you have that requirement.
RSA* privKey = NULL;
RSA* pubKey = NULL;
BIGNUM* exp = NULL;
privKey = RSA_new();
ASSERT(privKey != NULL);
exp = BN_new();
ASSERT(exp != NULL);
rc = BN_set_word(exp, RSA_F4);
ASSERT(rc == 1);
rc = RSA_generate_key_ex(privKey, 1024, exp, NULL);
ASSERT(rc == 1);
pubKey = RSAPublicKey_dup(privKey);
ASSERT(pubKey != NULL);
RSA_print_fp(stdout, pubKey, 0);
if(pubKey) {
RSA_free(pubKey);
}
if(privKey) {
RSA_free(privKey);
}
if(exp) {
BN_free(exp);
}
The RSA_print_fp results in:
$ ./t.exe
Public-Key: (1024 bit)
Modulus:
00:c3:30:67:d9:11:59:9b:85:7a:1a:95:fa:fd:c0:
dd:cd:21:d6:41:6b:16:70:c2:57:9a:f2:d2:bd:3b:
c0:02:7b:6a:ab:7f:13:a7:53:2f:31:10:08:3a:62:
28:40:5f:82:19:23:f6:0f:78:f5:e3:e4:19:a1:b4:
73:65:35:10:db:17:28:41:42:ba:df:8c:18:3b:d8:
62:52:65:61:0e:cd:60:28:c9:75:a8:5b:46:a4:89:
db:78:89:49:87:5d:7f:ce:d0:44:c4:fd:4a:74:66:
d4:46:21:c1:89:97:28:de:43:e9:94:50:f1:36:85:
a7:ef:6c:6d:6f:5d:78:00:67
Exponent: 65537 (0x10001)
You can add a call to PEM_write_RSAPublicKey:
FILE* file = fopen("rsa-pub.pem", "w");
ASSERT(file != NULL);
rc = PEM_write_RSAPublicKey(file, pubKey);
Then:
$ ./t.exe
$ cat rsa-pub.pem
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMb2jIVcTttHRqG9szv3CFZ742l7LxnVoM6oOfQXNOwabh+GB4Srf4IA
XRcGan7cj1DShnoPw9fp3IeuAUerk3xz8yPXCw09dLwrFcsmItLVnSLoRtpHnxN5
30Wd5vKpvKTLIQnurGo05s911ukFJeGo2y2OjSnTiQcJLUdt497tAgMBAAE=
-----END RSA PUBLIC KEY-----

How do I encrypt a string with an RSA public key from a ASN.1 x509 Byte array?

I have an ASN.1 x509 byte array that contains the modulo and the public key of an RSA pair. My goal is to do whatever it takes to use this to encrypt a string. I'm trying to use openssl in objective-c to accomplish this. Whenever I try to get an RSA object using d2i_X509, it returns null. I'm willing to switch to a different library if I can't accomplish this using openssl. Please help me find something that works.
You generally would not encrypt a string using the public key of an X.509 directly. Instead you would generate a strong random(of a specific quality) key; use normal symmetric encryption (such as AES) and then encyrpt the string with that. You then encrypt the random key with the X.509.
Consult a good PKI/Crypto book (e.g. http://www.amazon.com/Applied-Cryptography-Protocols-Algorithms-Source/dp/0471117099) as to why (sections on key leakage, bit-flipping, padding and (re)encrypting twice).
If you really insist on doing this -have a look at https://github.com/dirkx/smime-add-encryption-for-recipient/blob/master/smime-add-encrypt/main.c its pkcs7_encode_rinfo function.
x509cert = ... something to read your x509 byte array in.
unsigned char *stuff = "Some zecret string";
int stufflen = strlen(stuff);
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx = NULL;
assert(pkey = = X509_get_pubkey( x509cert));
assert(pctx = EVP_PKEY_CTX_new(pkey, NULL));
assert(EVP_PKEY_encrypt_init(pctx)==1);
assert((EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT
EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri)==1);
size_t eklen;
assert(EVP_PKEY_encrypt(pctx, NULL, &eklen, stuff, stufflen)==1);
ek = OPENSSL_malloc(eklen);
assert(ek);
unsigned char *ek = NULL;
assert((EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen)==1);
printf("Encrypted blurp: ");
for(int i = 0; i < eklen; i++) {
printf("0x%02X ", ek[i];
};
printf("\n");
exit(0);

Initialize Public Key From Modulus & Exponent using OpenSSL

Trying to generate an RSA Public Key given an APIs modulus and exponent. I'm using OpenSSL on iOS 4.2.
Generating the public key manually is an option (see below) however i'm not sure how to include the exponent logic in the modulus
-----BEGIN PUBLIC KEY-----
Modulus from API
-----END PUBLIC KEY-----
Based on #James comments, I am able to write public pem but getting blank private key. Here is my code:
char szModulus = "1162" ;
char *szExp = "827655" ;
RSA* rsa = RSA_new();
int ret = BN_hex2bn(&rsa->n,szModulus) ;
ret = BN_hex2bn(&rsa->d,szExp) ;
FILE *fp = fopen("/Users/ysi/Desktop/privateKey.pem", "wb");
PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, 0, NULL);
To do this make sure you have the OpenSSL library linked (instructions here http://code.google.com/p/ios-static-libraries/)
Once linked you'll have access to several BIGNUM converters. I turned the modulus into hex using the BN_hex2bn method saving the hex string into 'exponent'
Then create the BIGNUM struct and encrypt using RSA_public_encrypt
RSA *rsa = NULL;
rsa->n = BN_new();
BN_copy(rsa->n,modulus);
rsa->e = BN_new();
BN_copy(rsa->e,exponent);
rsa->iqmp=NULL;
rsa->d=NULL;
rsa->p=NULL;
rsa->q=NULL;
Good Luck!

How can I import an RSA public key from either XML or modulus/exponent in native code for use with Windows CAPI's CryptVerifySignature?

In C#, I am able to validate a hash against a public key in either of the following ways:
// Import from raw modulus and exponent
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) {
RSAParameters rsaKeyInfo = new RSAParameters {Modulus = modulus, Exponent = exponent};
rsa.ImportParameters(rsaKeyInfo);
return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA512"), signature);
}
// Import from XML
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) {
rsa.FromXmlString(xmlPublicKey);
return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA512"), signature);
}
What I need to know is how I can use CAPI to accomplish the same thing, given an inbound RSA public key?
I have most of the CAPI functions necessary to validate a hash, except for understanding how to import a public key into the cryptographic provider's context:
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);
CryptCreateHash(hCryptProv, CALG_SHA512, 0, 0, &hHash);
CryptHashData(hHash, pDataToHash, lenDataToHash, 0);
CryptVerifySignature(hHash, pSignature, sigLength, NULL, CRYPT_NOHASHOID);
CryptDestroyHash(hHash);
CryptReleaseContext(hCryptProv, 0);
Thanks!
Use CryptImportKey with a PUBLICKEYBLOB:
HCRYPTKEY hPublicKey;
DWORD keyBlobLength = sizeof(BLOBHEADER)+sizeof(RSAPUBKEY)+modulusLengthInBytes;
BYTE* keyBlob = malloc(keyBlobLength);
BLOBHEADER* blobheader = (BLOBHEADER*) keyBlob;
blobheader.bType = PUBLICKEYBLOB;
blobheader.bVersion = CUR_BLOB_VERSION;
blobheader.reserved = 0;
blobheader.aiKeyAlg = CALG_RSA_KEYX;
RSAPUBKEY* rsapubkey = (RSAPUBKEY*) (keyBlob + sizeof(BLOBHEADER));
rsapubkey.magic = 0x31415352;
rsapubkey.bitlen = modulusLengthInBytes*8;
rsapubkey.pubexp = 65537; // Or whatever your public exponent is.
BYTE* modulus = keyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY);
memcpy(modulus, ..., modulusLengthInBytes); // NOTE: modulus must be in LSB form,
// which is the opposite of what you
// usually have.
// .NET will give you the modulus in
// MSB form, so you will have to
// reverse the order of the bytes.
CryptImportKey(hCryptProv, keyBlob, keyBlobLength, 0, 0, &hPublicKey);