From 64106c4d3d4ddba8c7bc2af75376e6d3d3d75601 Mon Sep 17 00:00:00 2001 From: Date: Mon, 29 Jun 2015 20:16:15 +0000 Subject: Update documentation --- src/openssl/crypto/pkey.rs.html | 1103 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1103 insertions(+) create mode 100644 src/openssl/crypto/pkey.rs.html (limited to 'src/openssl/crypto/pkey.rs.html') diff --git a/src/openssl/crypto/pkey.rs.html b/src/openssl/crypto/pkey.rs.html new file mode 100644 index 0000000..4b93f74 --- /dev/null +++ b/src/openssl/crypto/pkey.rs.html @@ -0,0 +1,1103 @@ + + + + + + + + + + pkey.rs.html -- source + + + + + + + + + + + + + + + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+
+use libc::{c_int, c_uint, c_ulong};
+use std::io;
+use std::io::prelude::*;
+use std::iter::repeat;
+use std::mem;
+use std::ptr;
+use bio::{MemBio};
+use crypto::hash;
+use crypto::hash::Type as HashType;
+use ffi;
+use ssl::error::{SslError, StreamError};
+
+#[derive(Copy, Clone)]
+pub enum Parts {
+    Neither,
+    Public,
+    Both
+}
+
+/// Represents a role an asymmetric key might be appropriate for.
+#[derive(Copy, Clone)]
+pub enum Role {
+    Encrypt,
+    Decrypt,
+    Sign,
+    Verify
+}
+
+/// Type of encryption padding to use.
+#[derive(Copy, Clone)]
+pub enum EncryptionPadding {
+    OAEP,
+    PKCS1v15
+}
+
+fn openssl_padding_code(padding: EncryptionPadding) -> c_int {
+    match padding {
+        EncryptionPadding::OAEP => 4,
+        EncryptionPadding::PKCS1v15 => 1
+    }
+}
+
+fn openssl_hash_nid(hash: HashType) -> c_int {
+    match hash {
+        HashType::MD5       => 4,   // NID_md5,
+        HashType::SHA1      => 64,  // NID_sha1
+        HashType::SHA224    => 675, // NID_sha224
+        HashType::SHA256    => 672, // NID_sha256
+        HashType::SHA384    => 673, // NID_sha384
+        HashType::SHA512    => 674, // NID_sha512
+        HashType::RIPEMD160 => 117, // NID_ripemd160
+    }
+}
+
+pub struct PKey {
+    evp: *mut ffi::EVP_PKEY,
+    parts: Parts,
+}
+
+/// Represents a public key, optionally with a private key attached.
+impl PKey {
+    pub fn new() -> PKey {
+        unsafe {
+            ffi::init();
+
+            PKey {
+                evp: ffi::EVP_PKEY_new(),
+                parts: Parts::Neither,
+            }
+        }
+    }
+
+    pub fn from_handle(handle: *mut ffi::EVP_PKEY, parts: Parts) -> PKey {
+        ffi::init();
+        assert!(!handle.is_null());
+
+        PKey {
+            evp: handle,
+            parts: parts,
+        }
+    }
+
+    /// Reads private key from PEM, takes ownership of handle
+    pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError> where R: Read {
+        let mut mem_bio = try!(MemBio::new());
+        try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+
+        unsafe {
+            let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
+                                                                 ptr::null_mut(),
+                                                                 None, ptr::null_mut()));
+            Ok(PKey {
+                evp:   evp,
+                parts: Parts::Both,
+            })
+        }
+    }
+
+    fn _tostr(&self, f: unsafe extern "C" fn(*mut ffi::RSA, *const *mut u8) -> c_int) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = f(rsa, ptr::null());
+            if len < 0 as c_int { return vec!(); }
+            let mut s = repeat(0u8).take(len as usize).collect::<Vec<_>>();
+
+            let r = f(rsa, &s.as_mut_ptr());
+
+            s.truncate(r as usize);
+            s
+        }
+    }
+
+    fn _fromstr(&mut self, s: &[u8], f: unsafe extern "C" fn(*const *mut ffi::RSA, *const *const u8, c_uint) -> *mut ffi::RSA) {
+        unsafe {
+            let rsa = ptr::null_mut();
+            f(&rsa, &s.as_ptr(), s.len() as c_uint);
+            ffi::EVP_PKEY_set1_RSA(self.evp, rsa);
+        }
+    }
+
+    pub fn gen(&mut self, keysz: usize) {
+        unsafe {
+            let rsa = ffi::RSA_generate_key(
+                keysz as c_int,
+                65537 as c_ulong,
+                ptr::null(),
+                ptr::null()
+            );
+
+            // XXX: 6 == NID_rsaEncryption
+            ffi::EVP_PKEY_assign(
+                self.evp,
+                6 as c_int,
+                mem::transmute(rsa));
+
+            self.parts = Parts::Both;
+        }
+    }
+
+    /**
+     * Returns a serialized form of the public key, suitable for load_pub().
+     */
+    pub fn save_pub(&self) -> Vec<u8> {
+        self._tostr(ffi::i2d_RSA_PUBKEY)
+    }
+
+    /**
+     * Loads a serialized form of the public key, as produced by save_pub().
+     */
+    pub fn load_pub(&mut self, s: &[u8]) {
+        self._fromstr(s, ffi::d2i_RSA_PUBKEY);
+        self.parts = Parts::Public;
+    }
+
+    /**
+     * Returns a serialized form of the public and private keys, suitable for
+     * load_priv().
+     */
+    pub fn save_priv(&self) -> Vec<u8> {
+        self._tostr(ffi::i2d_RSAPrivateKey)
+    }
+    /**
+     * Loads a serialized form of the public and private keys, as produced by
+     * save_priv().
+     */
+    pub fn load_priv(&mut self, s: &[u8]) {
+        self._fromstr(s, ffi::d2i_RSAPrivateKey);
+        self.parts = Parts::Both;
+    }
+
+    /// Stores private key as a PEM
+    // FIXME: also add password and encryption
+    pub fn write_pem<W: Write>(&self, writer: &mut W/*, password: Option<String>*/) -> Result<(), SslError> {
+        let mut mem_bio = try!(MemBio::new());
+        unsafe {
+            try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(),
+                                                   ptr::null_mut(), -1, None, ptr::null_mut()));
+
+        }
+        let mut buf = vec![];
+        try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
+        writer.write_all(&buf).map_err(StreamError)
+    }
+
+    /**
+     * Returns the size of the public key modulus.
+     */
+    pub fn size(&self) -> usize {
+        unsafe {
+            ffi::RSA_size(ffi::EVP_PKEY_get1_RSA(self.evp)) as usize
+        }
+    }
+
+    /**
+     * Returns whether this pkey object can perform the specified role.
+     */
+    pub fn can(&self, r: Role) -> bool {
+        match r {
+            Role::Encrypt =>
+                match self.parts {
+                    Parts::Neither => false,
+                    _ => true,
+                },
+            Role::Verify =>
+                match self.parts {
+                    Parts::Neither => false,
+                    _ => true,
+                },
+            Role::Decrypt =>
+                match self.parts {
+                    Parts::Both => true,
+                    _ => false,
+                },
+            Role::Sign =>
+                match self.parts {
+                    Parts::Both => true,
+                    _ => false,
+                },
+        }
+    }
+
+    /**
+     * Returns the maximum amount of data that can be encrypted by an encrypt()
+     * call.
+     */
+    pub fn max_data(&self) -> usize {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+
+            // 41 comes from RSA_public_encrypt(3) for OAEP
+            len as usize - 41
+        }
+    }
+
+    pub fn encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+
+            assert!(s.len() < self.max_data());
+
+            let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
+
+            let rv = ffi::RSA_public_encrypt(
+                s.len() as c_int,
+                s.as_ptr(),
+                r.as_mut_ptr(),
+                rsa,
+                openssl_padding_code(padding));
+
+            if rv < 0 as c_int {
+                vec!()
+            } else {
+                r.truncate(rv as usize);
+                r
+            }
+        }
+    }
+
+    pub fn decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+
+            assert_eq!(s.len() as c_int, ffi::RSA_size(rsa));
+
+            let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
+
+            let rv = ffi::RSA_private_decrypt(
+                s.len() as c_int,
+                s.as_ptr(),
+                r.as_mut_ptr(),
+                rsa,
+                openssl_padding_code(padding));
+
+            if rv < 0 as c_int {
+                vec!()
+            } else {
+                r.truncate(rv as usize);
+                r
+            }
+        }
+    }
+
+    /**
+     * Encrypts data using OAEP padding, returning the encrypted data. The
+     * supplied data must not be larger than max_data().
+     */
+    pub fn encrypt(&self, s: &[u8]) -> Vec<u8> { self.encrypt_with_padding(s, EncryptionPadding::OAEP) }
+
+    /**
+     * Decrypts data, expecting OAEP padding, returning the decrypted data.
+     */
+    pub fn decrypt(&self, s: &[u8]) -> Vec<u8> { self.decrypt_with_padding(s, EncryptionPadding::OAEP) }
+
+    /**
+     * Signs data, using OpenSSL's default scheme and adding sha256 ASN.1 information to the
+     * signature.
+     * The bytes to sign must be the result of a sha256 hashing;
+     * returns the signature.
+     */
+    pub fn sign(&self, s: &[u8]) -> Vec<u8> { self.sign_with_hash(s, HashType::SHA256) }
+
+    /**
+     * Verifies a signature s (using OpenSSL's default scheme and sha256) on the SHA256 hash of a
+     * message.
+     * Returns true if the signature is valid, and false otherwise.
+     */
+    pub fn verify(&self, h: &[u8], s: &[u8]) -> bool { self.verify_with_hash(h, s, HashType::SHA256) }
+
+    /**
+     * Signs data, using OpenSSL's default scheme and add ASN.1 information for the given hash type to the
+     * signature.
+     * The bytes to sign must be the result of this type of hashing;
+     * returns the signature.
+     */
+    pub fn sign_with_hash(&self, s: &[u8], hash: hash::Type) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+            let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
+
+            let mut len = 0;
+            let rv = ffi::RSA_sign(
+                openssl_hash_nid(hash),
+                s.as_ptr(),
+                s.len() as c_uint,
+                r.as_mut_ptr(),
+                &mut len,
+                rsa);
+
+            if rv < 0 as c_int {
+                vec!()
+            } else {
+                r.truncate(len as usize);
+                r
+            }
+        }
+    }
+
+    pub fn verify_with_hash(&self, h: &[u8], s: &[u8], hash: hash::Type) -> bool {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+
+            let rv = ffi::RSA_verify(
+                openssl_hash_nid(hash),
+                h.as_ptr(),
+                h.len() as c_uint,
+                s.as_ptr(),
+                s.len() as c_uint,
+                rsa
+            );
+
+            rv == 1 as c_int
+        }
+    }
+
+    pub unsafe fn get_handle(&self) -> *mut ffi::EVP_PKEY {
+        return self.evp
+    }
+
+    pub fn public_eq(&self, other: &PKey) -> bool {
+        unsafe { ffi::EVP_PKEY_cmp(self.evp, other.evp) == 1 }
+    }
+}
+
+impl Drop for PKey {
+    fn drop(&mut self) {
+        unsafe {
+            ffi::EVP_PKEY_free(self.evp);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::path::Path;
+    use std::fs::File;
+    use crypto::hash::Type::{MD5, SHA1};
+
+    #[test]
+    fn test_gen_pub() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        assert_eq!(k0.save_pub(), k1.save_pub());
+        assert!(k0.public_eq(&k1));
+        assert_eq!(k0.size(), k1.size());
+        assert!(k0.can(super::Role::Encrypt));
+        assert!(k0.can(super::Role::Decrypt));
+        assert!(k0.can(super::Role::Verify));
+        assert!(k0.can(super::Role::Sign));
+        assert!(k1.can(super::Role::Encrypt));
+        assert!(!k1.can(super::Role::Decrypt));
+        assert!(k1.can(super::Role::Verify));
+        assert!(!k1.can(super::Role::Sign));
+    }
+
+    #[test]
+    fn test_gen_priv() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        k0.gen(512);
+        k1.load_priv(&k0.save_priv());
+        assert_eq!(k0.save_priv(), k1.save_priv());
+        assert!(k0.public_eq(&k1));
+        assert_eq!(k0.size(), k1.size());
+        assert!(k0.can(super::Role::Encrypt));
+        assert!(k0.can(super::Role::Decrypt));
+        assert!(k0.can(super::Role::Verify));
+        assert!(k0.can(super::Role::Sign));
+        assert!(k1.can(super::Role::Encrypt));
+        assert!(k1.can(super::Role::Decrypt));
+        assert!(k1.can(super::Role::Verify));
+        assert!(k1.can(super::Role::Sign));
+    }
+
+    #[test]
+    fn test_private_key_from_pem() {
+        let key_path = Path::new("test/key.pem");
+        let mut file = File::open(&key_path)
+            .ok()
+            .expect("Failed to open `test/key.pem`");
+
+        super::PKey::private_key_from_pem(&mut file).unwrap();
+    }
+
+    #[test]
+    fn test_encrypt() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        let emsg = k1.encrypt(&msg);
+        let dmsg = k0.decrypt(&emsg);
+        assert!(msg == dmsg);
+    }
+
+    #[test]
+    fn test_encrypt_pkcs() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        let emsg = k1.encrypt_with_padding(&msg, super::EncryptionPadding::PKCS1v15);
+        let dmsg = k0.decrypt_with_padding(&emsg, super::EncryptionPadding::PKCS1v15);
+        assert!(msg == dmsg);
+    }
+
+    #[test]
+    fn test_sign() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        let sig = k0.sign(&msg);
+        let rv = k1.verify(&msg, &sig);
+        assert!(rv == true);
+    }
+
+    #[test]
+    fn test_sign_hashes() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+
+        let sig = k0.sign_with_hash(&msg, MD5);
+
+        assert!(k1.verify_with_hash(&msg, &sig, MD5));
+        assert!(!k1.verify_with_hash(&msg, &sig, SHA1));
+    }
+
+    #[test]
+    fn test_eq() {
+        let mut k0 = super::PKey::new();
+        let mut p0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let mut p1 = super::PKey::new();
+        k0.gen(512);
+        k1.gen(512);
+        p0.load_pub(&k0.save_pub());
+        p1.load_pub(&k1.save_pub());
+
+        assert!(k0.public_eq(&k0));
+        assert!(k1.public_eq(&k1));
+        assert!(p0.public_eq(&p0));
+        assert!(p1.public_eq(&p1));
+        assert!(k0.public_eq(&p0));
+        assert!(k1.public_eq(&p1));
+
+        assert!(!k0.public_eq(&k1));
+        assert!(!p0.public_eq(&p1));
+        assert!(!k0.public_eq(&p1));
+        assert!(!p0.public_eq(&k1));
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3