summaryrefslogtreecommitdiff
path: root/ext/openssl
diff options
context:
space:
mode:
authoremboss <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-09 18:16:18 +0000
committeremboss <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-09 18:16:18 +0000
commit21f1af2ec217c6e64af2095186c558b81a00e212 (patch)
treead0ab957a0352deb6d81adf1ea1d85b3254efe07 /ext/openssl
parent14ba7fab58329201aebdc49b83ca96dfbf0b13e6 (diff)
* ext/openssl/ossl.c: Fix error in example. Patch by David Albert.
Add/extend existing documentation. Examples now also cover RSA signatures and PBKDF2. [ruby-core: 45154][ruby-trunk - Bug #6475] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35996 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/openssl')
-rw-r--r--ext/openssl/ossl.c119
1 files changed, 105 insertions, 14 deletions
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 7c8507050ca..da7d08ad495 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -455,7 +455,7 @@ ossl_debug_set(VALUE self, VALUE val)
* ahold of the key may use it unless it is encrypted. In order to securely
* export a key you may export it with a pass phrase.
*
- * cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ * cipher = OpenSSL::Cipher.new 'AES-128-CBC'
* pass_phrase = 'my secure pass phrase goes here'
*
* key_secure = key.export cipher, pass_phrase
@@ -489,35 +489,126 @@ ossl_debug_set(VALUE self, VALUE val)
*
* == RSA Encryption
*
- * RSA provides ecryption and decryption using the public and private keys.
+ * RSA provides encryption and decryption using the public and private keys.
* You can use a variety of padding methods depending upon the intended use of
* encrypted data.
*
+ * === Encryption & Decryption
+ *
+ * Asymmetric public/private key encryption is slow and victim to attack in
+ * cases where it is used without padding or directly to encrypt larger chunks
+ * of data. Typical use cases for RSA encryption involve "wrapping" a symmetric
+ * key with the public key of the recipient who would "unwrap" that symmetric
+ * key again using their private key.
+ * The following illustrates a simplified example of such a key transport
+ * scheme. It shouldn't be used in practice, though, standardized protocols
+ * should always be preferred.
+ *
+ * wrapped_key = key.public_encrypt key
+ *
+ * A symmetric key encrypted with the public key can only be decrypted with
+ * the corresponding private key of the recipient.
+ *
+ * original_key = key.private_decrypt wrapped_key
+ *
+ * By default PKCS#1 padding will be used, but it is also possible to use
+ * other forms of padding, see PKey::RSA for further details.
+ *
+ * === Signatures
+ *
+ * Using "private_encrypt" to encrypt some data with the private key is
+ * equivalent to applying a digital signature to the data. A verifying
+ * party may validate the signature by comparing the result of decrypting
+ * the signature with "public_decrypt" to the original data. However,
+ * OpenSSL::PKey already has methods "sign" and "verify" that handle
+ * digital signatures in a standardized way - "private_encrypt" and
+ * "public_decrypt" shouldn't be used in practice.
+ *
+ * To sign a document, a cryptographically secure hash of the document is
+ * computed first, which is then signed using the private key.
+ *
+ * digest = OpenSSL::Digest::SHA256.new
+ * signature = key.sign digest, document
+ *
+ * To validate the signature, again a hash of the document is computed and
+ * the signature is decrypted using the public key. The result is then
+ * compared to the hash just computed, if they are equal the signature was
+ * valid.
+ *
+ * digest = OpenSSL::Digest::SHA256.new
+ * if key.verify digest, signature, document
+ * puts 'Valid'
+ * else
+ * puts 'Invalid'
+ * end
+ *
+ * == PBKDF2 Password-based Encryption
+ *
+ * If supported by the underlying OpenSSL version used, Password-based
+ * Encryption should use the features of PKCS5. If not supported or if
+ * required by legacy applications, the older, less secure methods specified
+ * in RFC 2898 are also supported (see below).
+ *
+ * PKCS5 supports PBKDF2 as it was specified in PKCS#5
+ * v2.0[http://www.rsa.com/rsalabs/node.asp?id=2127]. It still uses a
+ * password, a salt, and additionally a number of iterations that will
+ * slow the key derivation process down. The slower this is, the more work
+ * it requires being able to brute-force the resulting key.
+ *
* === Encryption
+ *
+ * The strategy is to first instantiate a Cipher for encryption, and
+ * then to generate a random IV plus a key derived from the password
+ * using PBKDF2. PKCS #5 v2.0 recommends at least 8 bytes for the salt,
+ * the number of iterations largely depends on the hardware being used.
*
- * Documents encrypted with the public key can only be decrypted with the
- * private key.
+ * cipher = OpenSSL::Cipher.new 'AES-128-CBC'
+ * cipher.encrypt
+ * iv = cipher.random_iv
*
- * public_encrypted = key.public_encrypt 'top secret document'
+ * pwd = 'some hopefully not to easily guessable password'
+ * salt = OpenSSL::Random.random_bytes 16
+ * iter = 20000
+ * key_len = cipher.key_len
+ * digest = OpenSSL::Digest::SHA256.new
*
- * Documents encrypted with the private key can only be decrypted with the
- * public key.
+ * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
+ * cipher.key = key
*
- * private_encrypted = key.private_encrypt 'public release document'
+ * Now encrypt the data:
+ *
+ * encrypted = cipher.update document
+ * encrypted << cipher.final
*
* === Decryption
*
- * Use the opposite key type do decrypt the document
+ * Use the same steps as before to derive the symmetric AES key, this time
+ * setting the Cipher up for decryption.
+ *
+ * cipher = OpenSSL::Cipher.new 'AES-128-CBC'
+ * cipher.decrypt
+ * cipher.iv = iv # the one generated with #random_iv
+ *
+ * pwd = 'some hopefully not to easily guessable password'
+ * salt = ... # the one generated above
+ * iter = 20000
+ * key_len = cipher.key_len
+ * digest = OpenSSL::Digest::SHA256.new
+ *
+ * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
+ * cipher.key = key
*
- * top_secret = key.public_decrypt public_encrypted
+ * Now decrypt the data:
*
- * public_release = key.private_decrypt private_encrypted
+ * decrypted = cipher.update encrypted
+ * decrypted << cipher.final
*
* == PKCS #5 Password-based Encryption
*
* PKCS #5 is a password-based encryption standard documented at
* RFC2898[http://www.ietf.org/rfc/rfc2898.txt]. It allows a short password or
- * passphrase to be used to create a secure encryption key.
+ * passphrase to be used to create a secure encryption key. If possible, PBKDF2
+ * as described above should be used if the circumstances allow it.
*
* PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption
* key.
@@ -529,7 +620,7 @@ ossl_debug_set(VALUE self, VALUE val)
*
* First set up the cipher for encryption
*
- * encrypter = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ * encrypter = OpenSSL::Cipher.new 'AES-128-CBC'
* encrypter.encrypt
* encrypter.pkcs5_keyivgen pass_phrase, salt
*
@@ -542,7 +633,7 @@ ossl_debug_set(VALUE self, VALUE val)
*
* Use a new Cipher instance set up for decryption
*
- * decrypter = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ * decrypter = OpenSSL::Cipher.new 'AES-128-CBC'
* decrypter.decrypt
* decrypter.pkcs5_keyivgen pass_phrase, salt
*