Next: , Previous: , Up: SXEmacs OpenSSL API   [Contents][Index]


62.2.6 public key crypto systems

While keys for symmetric ciphers can be easily stored as strings, keys for asymmetric algorithms are more complex. The openssl API therefore provides a dedicated primitive type, called pkey. Pkey objects can contain key pairs – i.e. pairs of public keys and corresponding private keys, public keys, and also certificates. They are general container object for various subtypes such as RSA, DSA, EC, and DH keys.

However, you cannot directly create such a pkey object nor access nor modify parts of it. Pkey objects are actually meant as transporter objects to simplify those functions which need them.

Function: ossl-pkey-p object

Return t if object is a pkey, nil otherwise.

Function: ossl-pkey-size pkey

Return the size a public key pkey in bits.

Function: ossl-pkey-private-p pkey

Return non-nil if pkey contains private data.

Note: This function is not native OpenSSL.

Function: ossl-pkey-get-public pkey

Return a copy of pkey stripped by the private data.

Note: This function is not native OpenSSL.

The above functions have a generic character because they are independent from the choice of algorithm, see below. For each of these algorithms we provide a constructor function ossl-algo-generate-key and a subtype predicate, named ossl-algo-pkey-p. In case of RSA and DSA we also support a subkey check.

Note: At the moment we do not provide the creation of DH-keys.

Now the first important asymmetric algorithm is RSA. As mentioned in the general introduction OpenSSL can be built without it. The following functions therefore exist iff (featurep 'openssl-rsa) evaluates to t.

Function: ossl-rsa-generate-key bits exp

Return an RSA public key with of length bits and exponent exp.

Function: ossl-rsa-pkey-p pkey

Return t iff pkey is of RSA type.

Function: ossl-rsa-subkey-p pkey1 pkey2

Return t if pkey1 is a subkey of pkey2, nil otherwise, i.e. if pkey1 has the same public key data as pkey2 and pkey2 has all private data.

Note: This function is not native OpenSSL.

(setq rsaexmpl (ossl-rsa-generate-key 2048 3))
  ⇒ #<OpenSSL RSA private/public key, size 2048>
(ossl-rsa-pkey-p rsaexmpl)
  ⇒ t
(ossl-pkey-private-p rsaexmpl)
  ⇒ t
(setq rsapub (ossl-pkey-get-public rsaexmpl))
  ⇒ #<OpenSSL RSA public key, size 2048>
(ossl-pkey-private-p rsapub)
  ⇒ nil
(ossl-rsa-subkey-p rsapub rsaexmpl)
  ⇒ t

Another important asymmetric algorithm is DSA. The presence of DSA support in the underlying library can be checked by (featurep 'openssl-dsa). Nonetheless, it is very unlikely to face an OpenSSL installation without DSA or RSA.

Function: ossl-dsa-generate-key bits &optional seed

Return a DSA public key with of length bits seeded with (optional) seed.

Function: ossl-dsa-pkey-p pkey

Return t if pkey is of DSA type, nil otherwise.

Function: ossl-dsa-subkey-p pkey1 pkey2

Return t if pkey1 is a subkey of pkey2, nil otherwise, i.e. if pkey1 has the same public key data as pkey2 and pkey2 has all private data.

Note: This function is not native OpenSSL.

(setq dsaexmpl (ossl-dsa-generate-key 1024))
  ⇒ #<OpenSSL DSA private/public key, size 384>
(ossl-dsa-pkey-p dsaexmpl)
  ⇒ t
(ossl-pkey-private-p dsaexmpl)
  ⇒ t
(setq dsapub (ossl-pkey-get-public dsaexmpl))
  ⇒ #<OpenSSL DSA public key, size 384>
(ossl-pkey-private-p dsapub)
  ⇒ nil
(ossl-dsa-subkey-p dsapub dsaexmpl)
  ⇒ t

Elliptic curve cryptography is quite new and is possibly missing on many systems. Use (featurep 'openssl-ec) to check for elliptic curve support. Another particularity of the ec system is that it is based on a fixed set of curves which can be referred to by name. At the moment we do not support creating custom curves.

Function: ossl-ec-available-curves

Return a list of builtin elliptic curves.

Function: ossl-ec-generate-key curve

Return a EC public key on curve. curve may be any symbol from (ossl-ec-available-curves).

Note: At the moment we do not support creating custom curves.

Function: ossl-ec-pkey-p pkey

Return t if pkey is of EC type, nil otherwise.

(ossl-ec-available-curves)
  ⇒ (Oakley-EC2N-4 Oakley-EC2N-3 wap-wsg-idm-ecid-wtls12
      wap-wsg-idm-ecid-wtls11 wap-wsg-idm-ecid-wtls10
      wap-wsg-idm-ecid-wtls9 wap-wsg-idm-ecid-wtls8
      wap-wsg-idm-ecid-wtls7 wap-wsg-idm-ecid-wtls6
      wap-wsg-idm-ecid-wtls5 wap-wsg-idm-ecid-wtls4
      wap-wsg-idm-ecid-wtls3 wap-wsg-idm-ecid-wtls1 c2tnb431r1
      c2pnb368w1 c2tnb359v1 c2pnb304w1 c2pnb272w1 c2tnb239v3
      c2tnb239v2 c2tnb239v1 c2pnb208w1 c2tnb191v3 c2tnb191v2
      c2tnb191v1 c2pnb176v1 c2pnb163v3 c2pnb163v2 c2pnb163v1 sect571r1
      sect571k1 sect409r1 sect409k1 sect283r1 sect283k1 sect239k1
      sect233r1 sect233k1 sect193r2 sect193r1 sect163r2 sect163r1
      sect163k1 sect131r2 sect131r1 sect113r2 sect113r1 prime256v1
      prime239v3 prime239v2 prime239v1 prime192v3 prime192v2
      prime192v1 secp521r1 secp384r1 secp256k1 secp224r1 secp224k1
      secp192k1 secp160r2 secp160r1 secp160k1 secp128r2 secp128r1
      secp112r2 secp112r1)
(setq ecexmpl (ossl-ec-generate-key 'secp224r1))
  ⇒ #<OpenSSL EC private/public key, size 512>
(ossl-ec-pkey-p ecexmpl)
  => t
(ossl-pkey-private-p ecexmpl)
  ⇒ t
(setq ecpub (ossl-pkey-get-public ecexmpl))
  ⇒ #<OpenSSL EC public key, size 512>
(ossl-pkey-private-p ecpub)
  ⇒ nil

Finally, there is the DH key exchange. Its presence can be checked by (featurep 'openssl-dh). At the moment we do not provide constructor functions.

Function: ossl-dh-pkey-p pkey

Return t if pkey is of DH type, nil otherwise.

Once you have a pkey object you can use it for encryption/decryption, and/or signing/verification. Talking in OpenSSL hybrid encryption and decryption is referred to as sealing and opening, respectively.

Function: ossl-seal cipher string pkey

Return an envelope derived from encrypting string by cipher under pkey with the hybrid technique.

That is, create a random key/iv pair for the symmetric encryption with cipher and encrypt that key/iv asymmetrically with the provided public key.

The envelope returned is a list (encrypted_string encrypted_key encrypted_iv) where encrypted_string is the (symmetrically) encrypted message encrypted_key is the (asymmetrically) encrypted random key encrypted_iv is the (asymmetrically) encrypted random iv

Note: You probably want to put a wrapping encoder function (like base16-encode-string) around it, since this function returns binary string data.

Function: ossl-open cipher string pkey ekey eiv

Return the deciphered message string from an envelope obtained by ossl-seal.

In the following example we reuse the keys generated above.

(let ((envl
       (ossl-seal 'AES-256-CBC "I do not want to tell" rsaexmpl)))
  (setq str (car envl)
        key (nth 1 envl)
        iv (nth 2 envl))
  (mapcar #'base16-encode-string envl))
  ⇒ ("0e6a38b28efea3ca4901b268c141d7ac23ed5f8fa598d23d9846fe3ec1
       47278e"
      "167911a73b0a228b24e78bdd37197ec95b21bed3bbd62d1915d8fac791
       7915fd49fdd9774e7906ca53ed3bf4fb20de8339e628d469a496f7351c
       06fddda49b71c90e73e31c406cfb0f0fb7411d1c9d49842603c45415cc
       3a8f660c728e8f05c6479d004f5068a7969294b4cc81e13dd257df37dc
       886b11266a3ccba576396d200ebb1a3e8f7185fdbc6de40b63964562f9
       1cbe39118a07415c030fd4c3e25bbe2a64b2ab635b2ef9a71a5ddeeaf0
       4a73d7cd04ad334d1de04228db5a9fb9aebfa6a9dc9d76af5ec329b360
       d1cd8da45868450a3bc5c41bba95a0ad74439f7d5edffcdf7dff09c296
       35ae13215be1ae55f5d2b5e97d6a4d523470eef050b07193"
      "ab458ccb46cbc092c31614e997cd176b")
(ossl-open 'AES-256-CBC str rsaexmpl key iv)
  ⇒ "I do not want to tell"

The above example is nice but does not demonstrate the real power of hybrid encryption. In the following example we reuse the public subkey rsapub of rsaexmpl from above. Also you will notice that the random key/iv pair has changed and thus the resulting encrypted string is not the same.

(let ((envl
       (ossl-seal 'AES-256-CBC "I do not want to tell" rsapub)))
  (setq str (car envl)
        key (nth 1 envl)
        iv (nth 2 envl))
  (mapcar #'base16-encode-string envl))
  ⇒ ("93a5b3f2eb5a2eaee44805150717bb325b4e90be947591cc46b7819d3f
       4ec284"
      "300b9ab5a79524fdcb40fbed6bae7e9c470baa0d230f9b97c9b35de442
       62f82b626ef7668329d34cffc3eeddf535a879e974825e984c7e045c0a
       526b3b58453ae55926af519400f32c4aee7115088068fcb6fc75ce78c5
       b6d61bbaf90f0c4aff1d83efd63c45c62989c29efda187bcbd94edf9f1
       427ec8dce22cd6333e8196120285dc5bb224b9d7e9ecfb23e016475706
       5da6f999560d010adaf0465b108b2a84989ff8bd17778b61875f633a35
       a02c2cc1fdf3a3e50ad4a5fb7ad9a05b1a3a1818a21f3d7c71a33949f6
       437ee64bee60e1ae92ebea43ca524b15344a7fc2712e9758b98f1b2c9d
       c8ad3d074486f0d35fece7bf7b6ce979fa760aa7bd5854b2"
      "6979d574e8bc10dfddefd4cb017186a2")
(ossl-open 'AES-256-CBC str rsaexmpl key iv)
  ⇒ "I do not want to tell"
;; try with just the public part
(ossl-open 'AES-256-CBC str rsapub key iv)
error→ cannot open, key has no private key data

Also note you cannot use DSA keys for sealing. They are exclusively for signatures.

Signing and verifying works similar to sealing and opening. Instead of a cipher algorithm you need to specify a message digest algorithm. However, in this case the signature step requires a pkey with private data and the verification step can be done with only the public part of the key.

Function: ossl-sign digest string pkey

Return a signature obtained by signing string under digest with pkey.

That is, hash the message string with the message digest digest and encrypt the result with the private key pkey.

Note: Due to some relationship between the public key system and the message digest you cannot use every digest algorithm with every private key type. The most certain results will be achieved using RSA keys with RSA-* digests, DSA keys with DSA-* digests.

See ossl-available-digests.

Note: You probably want to put a wrapping encoder function (like base16-encode-string) around it, since this returns binary string data.

Function: ossl-verify digest string sig pkey

Return t iff sig is a valid signature of string under digest obtained by pkey.

That is, hash the message string with the message digest digest, then decrypt the signature sig with the public key pkey. Compare the results and return t iff both hashes are equal.

Again we reuse the keys defined above.

(progn
  (setq sig (ossl-sign 'SHA1 "I owe you a beer" dsaexmpl))
  (base16-encode-string sig))
  ⇒ "302d021500c2e5197d266573216e4daa85e0a7e43424d0f031021451186
      24043517e0cd24f381d0e6c92f96198f297"
(ossl-verify 'SHA1 "I owe you a beer" sig dsapub)
  ⇒ t
;; we try to fake the signed text
(ossl-verify 'SHA1 "I owe you 10 beer" sig dsapub)
  ⇒ nil

Note that you cannot use all combinations of pkey and digest algorithm. Suitable digests can be found in the (ossl-available-digests) list. Given a digest dgst there must be an entry RSA-dgst in order to use an RSA key for signatures under dgst. Respectively there must be an entry DSA-dgst for DSA key pairs and all DSA-suitable digests can also be used for EC keys.

In order to persistently store generated keys the openssl API provides a simple interface to the PEM routines. PEM is the format for key pairs or public keys.

Function: ossl-pem-read-public-key file

Return a key (the public part) stored in a PEM structure from file.

Function: ossl-pem-read-key file &optional password

Return a key stored in a PEM structure from file. If the (private part of the) key is protected with a password provide (optional) password.

Function: ossl-pem-write-public-key file pkey

Write pkey (the public part) in a PEM structure to file.

Function: ossl-pem-write-key file pkey &optional cipher password

Write pkey in a PEM structure to file. The key itself is protected by (optional) cipher with password.

cipher can be set to nil and the key will not be encrypted. password is ignored in this case.

Function: ossl-pem-public-key pkey

Return pkey as PEM encoded string.

Function: ossl-pem-key pkey &optional cipher password

Return pkey as PEM encoded string. The key itself is protected by (optional) cipher with password.

cipher can be set to nil and the key will not be encrypted. password is ignored in this case.

(ossl-pem-write-key "/tmp/mykey.pem" dsaexmpl)
(let ((stored (ossl-pem-read-key "/tmp/mykey.pem")))
  (ossl-verify 'SHA1 "I owe you a beer" sig stored))
  ⇒ t
(ossl-pem-public-key rsapub)
  ⇒ "-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAtGE7JaGUsVIfLUJmzlkR
qfB7CJjFlYU7tGmD7C1rBiGz0sjTlPwsMjwwCLP6byRvebVeDxGrxbeyZE3sSB4q
oVbevhbwwBMY5+j/8q+3l7KbqoP9CGG40ZbEC6IOqFn8kOmliPdWUlogI1Gr4b7U
R4F+TM6m3r3AQoxeqq+rR5kHat2mvBpxm0o8FZ2KW6ZCAkAXoA3NNCXtSUF9zA6A
u3acUP4eiFAkS4Q6hIuZli4PzxvUugB5/ekyaa5cRzIEqIhh90mkpqjM9qpR15hk
39qiM/SxXmLlncU534byldSgnoIse3tnia4WRBm2qK3zTr24zaBtTTXfmRJMWQwZ
ewIBAw==
-----END PUBLIC KEY-----
"
(ossl-pem-public-key rsaexmpl)
  ⇒ "-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAtGE7JaGUsVIfLUJmzlkR
qfB7CJjFlYU7tGmD7C1rBiGz0sjTlPwsMjwwCLP6byRvebVeDxGrxbeyZE3sSB4q
oVbevhbwwBMY5+j/8q+3l7KbqoP9CGG40ZbEC6IOqFn8kOmliPdWUlogI1Gr4b7U
R4F+TM6m3r3AQoxeqq+rR5kHat2mvBpxm0o8FZ2KW6ZCAkAXoA3NNCXtSUF9zA6A
u3acUP4eiFAkS4Q6hIuZli4PzxvUugB5/ekyaa5cRzIEqIhh90mkpqjM9qpR15hk
39qiM/SxXmLlncU534byldSgnoIse3tnia4WRBm2qK3zTr24zaBtTTXfmRJMWQwZ
ewIBAw==
-----END PUBLIC KEY-----
"
(ossl-pem-key rsaexmpl 'AES-256-CBC "foobar")
  ⇒ "-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIk4VVj28lKIgCAggA
MB0GCWCGSAFlAwQBKgQQ0uzDwfFB2m5ZUCt8K1YSvwSCBNCcQuY1S1c7Blsm7QlH
iHji7xWcigj6U7U6IQ0y/a6+U/ku2/IQc4I/sjsYNj1ZKBjkHxuWqVtGvKD/AB/r
2XFYkOpg7X2SvpVXuCkHk/B7l8ifQViqwu3k8r+8jHmLuxa21xysrTLOef8LmCkg
ePaOArDKascJngpkUtMM269owh1ZBUSmKqQqR+jnpXw+dummdlr2tA0t3Bl+899q
e6L7sZ330XRTnzyQUuZvBpV8bV0AlaI3jlPROu56MKiUiDU0n9lvzYegWGAJjOvS
qYW3FPY/B7MczXCFQOmg3XWXWJ/2szRQnWvuM5imhwVF4YbPO30H6KG2sRc5u4Bs
vym71CdlD77+YEw2dQ36bgjLE2v9aFIuuqqRlbNO1wUo1D0JFrN0ivGnliA6tCQ2
tADHeEqKeXjCk4GM+rZB9d/kx2RqTgqu+JolaO1+8lxWRMT+aLj5EPN8zHOaRhDL
3farG89PEOUvPRzkn+18laPBJ0o9AvwYC9Bmi072Lq7XtOIH0iELxY2RyQD0PLD2
cLdt5tkQDfuUhrUJuhh3waMDa7qe9lMGnxsmlapZn5FY1kZ6gBO79BBu9sFmsr1x
IRDT5PJc2V+BU9fn3Vu6WM3P56x7WfUjycqpvmu7yshW8D/8KRNYbeBIAXuRKCoJ
dRIp/c+UWSPDVb68NikRvTRvj0vVrGMsesRkl89uL6liGarGghEV9lwNDQB5XN0q
wZ+4LXP4DZQlBK3g9Bq7rL6F3ZuxGdThjQO6IAve6MltfOIN/x/schcoE41g2y0D
0hn8vnDkGwWKFE59qOZ7/iQOOKJisF6MjxnkhlcTvG3ev2mrSsJHdiIoN9u8Zm6o
Xca/k7JEs3rkr5MhrjxpGznq6Z5skEWEFFGD5XlXKYsHlP5YDxVXLED1cQHKcydC
t2uPsB/Uqj4zl/lBc0/asQ8gyZiR2Fc5DHjUkmQ/5kH4LulvVLJgCC8JRs2AutBu
DsqfvEj8uhmCuNYlsrOGrrOo/m2HPQ1DeoJcoL+H8KQG1WjPo0bnaV0Xlf6o+IkI
G42pDGVeNSZDc+gqbXTzHDF0snOVDO7nfJ+kWmTFpHhI8Ht5H6SaaAIcgIQcWZgZ
vA7e54XQ6HBUARFaPdw8kXyilu3lGunacjfipCdsOaF3WxGgdPmQTfuQOqglYhlc
v/WPjyV9WgpEaJKM2Vcwb+CiOeteKnqp9ZLdmb4fZJNP2oIlKLtQSHsmdFGEr7BP
7hxoi/kcD9QpuC9CHn1rZC99ZwWBa+UmK5s+P8LJRfi6a8qhR3gA6H/JGZLFiW0C
Vrmir9u33UkroKfn+JTuMZV5e+U7YNFSJhX95nbLTIx44ItyztGlE5+lHMPA+N/p
+OQM2F0kzfSZ2F1M3x3iO4VPzfEC6vNBpOOhhssSoL9ThNYlCQOVa+QemEjmVuEs
PLluotrTI3Cetk4nanvj4HGb6KjnkU1JdQ6iKSEl2JnYWrmNNoB3N06/h/7DQpiy
p/tevEVZQxK2cOklJrgcuNtVXe3c/9OVRKDuu3m1GstbQ4pcqijc55kuEtA0tmvn
S5WFFj4/cVucd2K3IOHCttEfgDwVNDDzG2shBsKT1JDY4aDOBD3xe+ggstVkGmRL
ocNNE7QyxF/GOgW9iTQr/yOp9A==
-----END ENCRYPTED PRIVATE KEY-----
"

Next: , Previous: , Up: SXEmacs OpenSSL API   [Contents][Index]