Loading README.md 0 → 100644 +21 −0 Original line number Diff line number Diff line This package provides Rust bindings for the functionality exposed by OpenSSL's libcrypto. Currently provided: * Hashes (hash.rs) * MD5 * SHA-1 * SHA-2 (224, 256, 384, 512) * Symmetric crypto (symm.rs) * AES in ECB or CBC mode, all key lengths * Keypair generation (pkey.rs) * RSA, all key lengths * Asymmetric encryption (pkey.rs) * RSA with PKCS#1 OAEP padding * Digital signatures (pkey.rs) * RSA with whatever your system openssl does (PKCS#1 on my system) and sha256 Each module provides two interfaces: a low-level API which wraps the OpenSSL interfaces as directly as possible and a high-level API which presents the OpenSSL API as a Rust object and tries to make sensible default choices about parameters most users won't care about. You probably want to use the high-level API. For documentation on these, see the individual source files. crypto.rc 0 → 100644 +24 −0 Original line number Diff line number Diff line /* * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #[link(name = "crypto", vers = "0.1", uuid = "38297409-b4c2-4499-8131-a99a7e44dad3")]; #[crate_type = "lib"]; mod hash; mod pkey; mod symm; hash.rs 0 → 100644 +169 −0 Original line number Diff line number Diff line use std; import std::ptr; import std::str; import std::vec; export hasher; export hashtype; export mk_hasher; export hash; export _native; export md5, sha1, sha224, sha256, sha384, sha512; type hasher = obj { /* Method: init Initializes this hasher */ fn init(); /* Method: update Update this hasher with more input bytes */ fn update([u8]); /* Method: final Return the digest of all bytes added to this hasher since its last initialization */ fn final() -> [u8]; }; tag hashtype { md5; sha1; sha224; sha256; sha384; sha512; } #[link_name = "crypto"] #[abi = "cdecl"] native mod _native { type EVP_MD_CTX; type EVP_MD; fn EVP_MD_CTX_create() -> EVP_MD_CTX; fn EVP_md5() -> EVP_MD; fn EVP_sha1() -> EVP_MD; fn EVP_sha224() -> EVP_MD; fn EVP_sha256() -> EVP_MD; fn EVP_sha384() -> EVP_MD; fn EVP_sha512() -> EVP_MD; fn EVP_DigestInit(ctx: EVP_MD_CTX, typ: EVP_MD); fn EVP_DigestUpdate(ctx: EVP_MD_CTX, data: *u8, n: uint); fn EVP_DigestFinal(ctx: EVP_MD_CTX, res: *u8, n: *u32); } fn evpmd(t: hashtype) -> (_native::EVP_MD, uint) { alt t { md5. { (_native::EVP_md5(), 16u) } sha1. { (_native::EVP_sha1(), 20u) } sha224. { (_native::EVP_sha224(), 28u) } sha256. { (_native::EVP_sha256(), 32u) } sha384. { (_native::EVP_sha384(), 48u) } sha512. { (_native::EVP_sha512(), 64u) } } } fn mk_hasher(ht: hashtype) -> hasher { type hasherstate = { evp: _native::EVP_MD, ctx: _native::EVP_MD_CTX, len: uint }; obj hasher(st: hasherstate) { fn init() unsafe { _native::EVP_DigestInit(st.ctx, st.evp); } fn update(data: [u8]) unsafe { let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data); _native::EVP_DigestUpdate(st.ctx, pdata, vec::len(data)); } fn final() -> [u8] unsafe { let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, st.len); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); _native::EVP_DigestFinal(st.ctx, pres, ptr::null::<u32>()); vec::from_mut::<u8>(res) } } let ctx = _native::EVP_MD_CTX_create(); let (evp, mdlen) = evpmd(ht); let st = { evp: evp, ctx: ctx, len: mdlen }; let h = hasher(st); h.init(); ret h; } /* Function: hash Hashes the supplied input data using hash t, returning the resulting hash value */ fn hash(t: hashtype, data: [u8]) -> [u8] unsafe { let ctx = _native::EVP_MD_CTX_create(); let (evp, mdlen) = evpmd(t); let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, mdlen); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data); _native::EVP_DigestInit(ctx, evp); _native::EVP_DigestUpdate(ctx, pdata, vec::len(data)); _native::EVP_DigestFinal(ctx, pres, ptr::null::<u32>()); ret vec::from_mut::<u8>(res); } #[cfg(test)] mod tests { // Test vectors from http://www.nsrl.nist.gov/testdata/ #[test] fn test_md5() { let s0 = [0x61u8, 0x62u8, 0x63u8]; let d0 = [0x90u8, 0x01u8, 0x50u8, 0x98u8, 0x3cu8, 0xd2u8, 0x4fu8, 0xb0u8, 0xd6u8, 0x96u8, 0x3fu8, 0x7du8, 0x28u8, 0xe1u8, 0x7fu8, 0x72u8]; assert(hash(md5, s0) == d0); } #[test] fn test_sha1() { let s0 = [0x61u8, 0x62u8, 0x63u8]; let d0 = [0xa9u8, 0x99u8, 0x3eu8, 0x36u8, 0x47u8, 0x06u8, 0x81u8, 0x6au8, 0xbau8, 0x3eu8, 0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xc2u8, 0x6cu8, 0x9cu8, 0xd0u8, 0xd8u8, 0x9du8]; assert(hash(sha1, s0) == d0); } #[test] fn test_sha256() { let s0 = [0x61u8, 0x62u8, 0x63u8]; let d0 = [0xbau8, 0x78u8, 0x16u8, 0xbfu8, 0x8fu8, 0x01u8, 0xcfu8, 0xeau8, 0x41u8, 0x41u8, 0x40u8, 0xdeu8, 0x5du8, 0xaeu8, 0x22u8, 0x23u8, 0xb0u8, 0x03u8, 0x61u8, 0xa3u8, 0x96u8, 0x17u8, 0x7au8, 0x9cu8, 0xb4u8, 0x10u8, 0xffu8, 0x61u8, 0xf2u8, 0x00u8, 0x15u8, 0xadu8]; assert(hash(sha256, s0) == d0); } } fn main() { let h = mk_hasher(sha512); h.init(); h.update(str::bytes("")); log h.final(); log hash(sha512, str::bytes("")); } pkey.rs 0 → 100644 +351 −0 Original line number Diff line number Diff line use std; import std::ptr; import std::str; import std::unsafe; import std::vec; export pkeyrole, encrypt, decrypt, sign, verify; export pkey, mk_pkey; export _native; #[link_name = "crypto"] #[abi = "cdecl"] native mod _native { type EVP_PKEY; type ANYKEY; type RSA; fn EVP_PKEY_new() -> *EVP_PKEY; fn EVP_PKEY_free(k: *EVP_PKEY); fn EVP_PKEY_assign(k: *EVP_PKEY, t: int, inner: *ANYKEY); fn EVP_PKEY_get0(k: *EVP_PKEY) -> *ANYKEY; fn i2d_PublicKey(k: *EVP_PKEY, buf: **u8) -> int; fn d2i_PublicKey(t: int, k: **EVP_PKEY, buf: **u8, len: uint) -> *EVP_PKEY; fn i2d_PrivateKey(k: *EVP_PKEY, buf: **u8) -> int; fn d2i_PrivateKey(t: int, k: **EVP_PKEY, buf: **u8, len: uint) -> *EVP_PKEY; fn RSA_generate_key(modsz: uint, e: uint, cb: *u8, cbarg: *u8) -> *RSA; fn RSA_size(k: *RSA) -> uint; fn RSA_public_encrypt(flen: uint, from: *u8, to: *u8, k: *RSA, pad: int) -> int; fn RSA_private_decrypt(flen: uint, from: *u8, to: *u8, k: *RSA, pad: int) -> int; fn RSA_sign(t: int, m: *u8, mlen: uint, sig: *u8, siglen: *uint, k: *RSA) -> int; fn RSA_verify(t: int, m: *u8, mlen: uint, sig: *u8, siglen: uint, k: *RSA) -> int; } tag pkeyparts { neither; public; both; } /* Tag: pkeyrole Represents a role an asymmetric key might be appropriate for. */ tag pkeyrole { encrypt; decrypt; sign; verify; } /* Object: pkey Represents a public key, optionally with a private key attached. */ type pkey = obj { /* Method: save_pub Returns a serialized form of the public key, suitable for load_pub(). */ fn save_pub() -> [u8]; /* Method: load_pub Loads a serialized form of the public key, as produced by save_pub(). */ fn load_pub(s: [u8]); /* Method: save_priv Returns a serialized form of the public and private keys, suitable for load_priv(). */ fn save_priv() -> [u8]; /* Method: load_priv Loads a serialized form of the public and private keys, as produced by save_priv(). */ fn load_priv(s: [u8]); /* Method: size() Returns the size of the public key modulus. */ fn size() -> uint; /* Method: gen() Generates a public/private keypair of the specified size. */ fn gen(keysz: uint); /* Method: can() Returns whether this pkey object can perform the specified role. */ fn can(role: pkeyrole) -> bool; /* Method: max_data() Returns the maximum amount of data that can be encrypted by an encrypt() call. */ fn max_data() -> uint; /* Method: encrypt() Encrypts data using OAEP padding, returning the encrypted data. The supplied data must not be larger than max_data(). */ fn encrypt(s: [u8]) -> [u8]; /* Method: decrypt() Decrypts data, expecting OAEP padding, returning the decrypted data. */ fn decrypt(s: [u8]) -> [u8]; /* Method: sign() Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(), can process an arbitrary amount of data; returns the signature. */ fn sign(s: [u8]) -> [u8]; /* Method: verify() Verifies a signature s (using OpenSSL's default scheme and sha256) on a message m. Returns true if the signature is valid, and false otherwise. */ fn verify(m: [u8], s: [u8]) -> bool; }; fn rsa_to_any(rsa: *_native::RSA) -> *_native::ANYKEY unsafe { unsafe::reinterpret_cast::<*_native::RSA, *_native::ANYKEY>(rsa) } fn any_to_rsa(anykey: *_native::ANYKEY) -> *_native::RSA unsafe { unsafe::reinterpret_cast::<*_native::ANYKEY, *_native::RSA>(anykey) } fn mk_pkey() -> pkey { type pkeystate = { mutable evp: *_native::EVP_PKEY, mutable parts: pkeyparts }; fn _tostr(st: pkeystate, f: fn@(*_native::EVP_PKEY, **u8) -> int) -> [u8] unsafe { let len = f(st.evp, ptr::null()); if len < 0 { ret []; } let s: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len as uint); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); let pps: **u8 = ptr::addr_of(ps); let r = f(st.evp, pps); let bytes = vec::slice::<u8>(s, 0u, r as uint); ret bytes; } fn _fromstr(st: pkeystate, f: fn@(int, **_native::EVP_PKEY, **u8, uint) -> *_native::EVP_PKEY, s: [u8]) unsafe { let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); let pps: **u8 = ptr::addr_of(ps); let evp: *_native::EVP_PKEY = ptr::null(); let pevp: **_native::EVP_PKEY = ptr::addr_of(evp); f(6, pevp, pps, vec::len(s)); st.evp = *pevp; } obj pkey(st: pkeystate) { fn gen(keysz: uint) unsafe { let rsa = _native::RSA_generate_key(keysz, 65537u, ptr::null(), ptr::null()); let rsa_ = rsa_to_any(rsa); // XXX: 6 == NID_rsaEncryption _native::EVP_PKEY_assign(st.evp, 6, rsa_); st.parts = both; } fn save_pub() -> [u8] { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::i2d_PublicKey(_, _); _tostr(st, f) } fn load_pub(s: [u8]) { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::d2i_PublicKey(_, _, _, _); _fromstr(st, f, s); st.parts = public; } fn save_priv() -> [u8] { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::i2d_PrivateKey(_, _); _tostr(st, f) } fn load_priv(s: [u8]) { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::d2i_PrivateKey(_, _, _, _); _fromstr(st, f, s); st.parts = both; } fn size() -> uint { _native::RSA_size(any_to_rsa(_native::EVP_PKEY_get0(st.evp))) } fn can(r: pkeyrole) -> bool { alt r { encrypt. { st.parts != neither } verify. { st.parts != neither } decrypt. { st.parts == both } sign. { st.parts == both } } } fn max_data() -> uint unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); // 41 comes from RSA_public_encrypt(3) for OAEP ret len - 41u; } fn encrypt(s: [u8]) -> [u8] unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); // 41 comes from RSA_public_encrypt(3) for OAEP assert(vec::len(s) < _native::RSA_size(rsa) - 41u); let r: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len + 1u); let pr: *u8 = vec::unsafe::to_ptr::<u8>(r); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); // XXX: 4 == RSA_PKCS1_OAEP_PADDING let rv = _native::RSA_public_encrypt(vec::len(s), ps, pr, rsa, 4); if rv < 0 { ret []; } ret vec::slice::<u8>(r, 0u, rv as uint); } fn decrypt(s: [u8]) -> [u8] unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); assert(vec::len(s) == _native::RSA_size(rsa)); let r: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len + 1u); let pr: *u8 = vec::unsafe::to_ptr::<u8>(r); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); // XXX: 4 == RSA_PKCS1_OAEP_PADDING let rv = _native::RSA_private_decrypt(vec::len(s), ps, pr, rsa, 4); if rv < 0 { ret []; } ret vec::slice::<u8>(r, 0u, rv as uint); } fn sign(s: [u8]) -> [u8] unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); let r: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len + 1u); let pr: *u8 = vec::unsafe::to_ptr::<u8>(r); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); let plen: *uint = ptr::addr_of(len); // XXX: 672 == NID_sha256 let rv = _native::RSA_sign(672, ps, vec::len(s), pr, plen, rsa); if rv < 0 { ret []; } ret vec::slice::<u8>(r, 0u, *plen as uint); } fn verify(m: [u8], s: [u8]) -> bool unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let pm: *u8 = vec::unsafe::to_ptr::<u8>(m); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); // XXX: 672 == NID_sha256 let rv = _native::RSA_verify(672, pm, vec::len(m), ps, vec::len(s), rsa); ret rv == 1; } } let st = { mutable evp: _native::EVP_PKEY_new(), mutable parts: neither }; let p = pkey(st); ret p; } #[cfg(test)] mod tests { #[test] fn test_gen_pub() { let k0 = mk_pkey(); let k1 = mk_pkey(); k0.gen(512u); k1.load_pub(k0.save_pub()); assert(k0.save_pub() == k1.save_pub()); assert(k0.size() == k1.size()); assert(k0.can(encrypt)); assert(k0.can(decrypt)); assert(k0.can(verify)); assert(k0.can(sign)); assert(k1.can(encrypt)); assert(!k1.can(decrypt)); assert(k1.can(verify)); assert(!k1.can(sign)); } #[test] fn test_gen_priv() { let k0 = mk_pkey(); let k1 = mk_pkey(); k0.gen(512u); k1.load_priv(k0.save_priv()); assert(k0.save_priv() == k1.save_priv()); assert(k0.size() == k1.size()); assert(k0.can(encrypt)); assert(k0.can(decrypt)); assert(k0.can(verify)); assert(k0.can(sign)); assert(k1.can(encrypt)); assert(k1.can(decrypt)); assert(k1.can(verify)); assert(k1.can(sign)); } #[test] fn test_encrypt() { let k0 = mk_pkey(); let k1 = mk_pkey(); let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; k0.gen(512u); k1.load_pub(k0.save_pub()); let emsg = k1.encrypt(msg); let dmsg = k0.decrypt(emsg); assert(msg == dmsg); } #[test] fn test_sign() { let k0 = mk_pkey(); let k1 = mk_pkey(); let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; k0.gen(512u); k1.load_pub(k0.save_pub()); let sig = k0.sign(msg); let rv = k1.verify(msg, sig); assert(rv == true); } } symm.rs 0 → 100644 +198 −0 Original line number Diff line number Diff line use std; import std::ptr; import std::str; import std::vec; export crypter; export cryptermode; export encryptmode, decryptmode; export cryptertype; export aes_256_ecb, aes_256_cbc; export mk_crypter; export encrypt, decrypt; export _native; #[link_name = "crypto"] #[abi = "cdecl"] native mod _native { type EVP_CIPHER_CTX; type EVP_CIPHER; fn EVP_CIPHER_CTX_new() -> EVP_CIPHER_CTX; fn EVP_CIPHER_CTX_set_padding(ctx: EVP_CIPHER_CTX, padding: int); fn EVP_aes_128_ecb() -> EVP_CIPHER; fn EVP_aes_128_cbc() -> EVP_CIPHER; fn EVP_aes_192_ecb() -> EVP_CIPHER; fn EVP_aes_192_cbc() -> EVP_CIPHER; fn EVP_aes_256_ecb() -> EVP_CIPHER; fn EVP_aes_256_cbc() -> EVP_CIPHER; fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER, key: *u8, iv: *u8, mode: int); fn EVP_CipherUpdate(ctx: EVP_CIPHER_CTX, outbuf: *u8, outlen: *u32, inbuf: *u8, inlen: u32); fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *u8, len: *u32); } /* Object: crypter Represents a symmetric cipher context. */ type crypter = obj { /* Method: pad Enables or disables padding. If padding is disabled, total amount of data encrypted must be a multiple of block size. */ fn pad(padding: bool); /* Method: init Initializes this crypter. */ fn init(mode: cryptermode, key: [u8], iv: [u8]); /* Method: update Update this crypter with more data to encrypt or decrypt. Returns encrypted or decrypted bytes. */ fn update(data: [u8]) -> [u8]; /* Method: final Finish crypting. Returns the remaining partial block of output, if any. */ fn final() -> [u8]; }; tag cryptermode { encryptmode; decryptmode; } tag cryptertype { aes_256_ecb; aes_256_cbc; } fn evpc(t: cryptertype) -> (_native::EVP_CIPHER, uint, uint) { alt t { aes_256_ecb. { (_native::EVP_aes_256_ecb(), 32u, 16u) } aes_256_cbc. { (_native::EVP_aes_256_cbc(), 32u, 16u) } } } fn mk_crypter(t: cryptertype) -> crypter { type crypterstate = { evp: _native::EVP_CIPHER, ctx: _native::EVP_CIPHER_CTX, keylen: uint, blocksize: uint }; obj crypter(st: crypterstate) { fn pad(padding: bool) { let v = padding ? 1 : 0; _native::EVP_CIPHER_CTX_set_padding(st.ctx, v); } fn init (mode: cryptermode, key: [u8], iv: [u8]) unsafe { let m = alt mode { encryptmode. { 1 } decryptmode. { 0 } }; assert(vec::len(key) == st.keylen); let pkey: *u8 = vec::unsafe::to_ptr::<u8>(key); let piv: *u8 = vec::unsafe::to_ptr::<u8>(iv); _native::EVP_CipherInit(st.ctx, st.evp, pkey, piv, m); } fn update(data: [u8]) -> [u8] unsafe { let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data); let datalen: u32 = vec::len(data) as u32; let reslen: u32 = datalen + (st.blocksize as u32); let preslen: *u32 = ptr::addr_of(reslen); let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, reslen as uint); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); _native::EVP_CipherUpdate(st.ctx, pres, preslen, pdata, datalen); ret vec::slice::<u8>(res, 0u, *preslen as uint); } fn final() -> [u8] unsafe { let reslen: u32 = st.blocksize as u32; let preslen: *u32 = ptr::addr_of(reslen); let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, reslen as uint); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); _native::EVP_CipherFinal(st.ctx, pres, preslen); ret vec::slice::<u8>(res, 0u, *preslen as uint); } } let ctx = _native::EVP_CIPHER_CTX_new(); let (evp, keylen, blocksz) = evpc(t); let st = { evp: evp, ctx: ctx, keylen: keylen, blocksize: blocksz }; let h = crypter(st); ret h; } /* Function: encrypt Encrypts data, using the specified crypter type in encrypt mode with the specified key and iv; returns the resulting (encrypted) data. */ fn encrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] { let c = mk_crypter(t); c.init(encryptmode, key, iv); let r = c.update(data); let rest = c.final(); ret r + rest; } /* Function: decrypt Decrypts data, using the specified crypter type in decrypt mode with the specified key and iv; returns the resulting (decrypted) data. */ fn decrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] { let c = mk_crypter(t); c.init(decryptmode, key, iv); let r = c.update(data); let rest = c.final(); ret r + rest; } #[cfg(test)] mod tests { // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf #[test] fn test_aes_256_ecb() { let k0 = [ 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0au8, 0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8, 0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8, 0x16u8, 0x17u8, 0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8 ]; let p0 = [ 0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8, 0x88u8, 0x99u8, 0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8 ]; let c0 = [ 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8 ]; let c = mk_crypter(aes_256_ecb); c.init(encryptmode, k0, []); c.pad(false); let r0 = c.update(p0) + c.final(); assert(r0 == c0); c.init(decryptmode, k0, []); c.pad(false); let p1 = c.update(r0) + c.final(); assert(p1 == p0); } } Loading
README.md 0 → 100644 +21 −0 Original line number Diff line number Diff line This package provides Rust bindings for the functionality exposed by OpenSSL's libcrypto. Currently provided: * Hashes (hash.rs) * MD5 * SHA-1 * SHA-2 (224, 256, 384, 512) * Symmetric crypto (symm.rs) * AES in ECB or CBC mode, all key lengths * Keypair generation (pkey.rs) * RSA, all key lengths * Asymmetric encryption (pkey.rs) * RSA with PKCS#1 OAEP padding * Digital signatures (pkey.rs) * RSA with whatever your system openssl does (PKCS#1 on my system) and sha256 Each module provides two interfaces: a low-level API which wraps the OpenSSL interfaces as directly as possible and a high-level API which presents the OpenSSL API as a Rust object and tries to make sensible default choices about parameters most users won't care about. You probably want to use the high-level API. For documentation on these, see the individual source files.
crypto.rc 0 → 100644 +24 −0 Original line number Diff line number Diff line /* * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #[link(name = "crypto", vers = "0.1", uuid = "38297409-b4c2-4499-8131-a99a7e44dad3")]; #[crate_type = "lib"]; mod hash; mod pkey; mod symm;
hash.rs 0 → 100644 +169 −0 Original line number Diff line number Diff line use std; import std::ptr; import std::str; import std::vec; export hasher; export hashtype; export mk_hasher; export hash; export _native; export md5, sha1, sha224, sha256, sha384, sha512; type hasher = obj { /* Method: init Initializes this hasher */ fn init(); /* Method: update Update this hasher with more input bytes */ fn update([u8]); /* Method: final Return the digest of all bytes added to this hasher since its last initialization */ fn final() -> [u8]; }; tag hashtype { md5; sha1; sha224; sha256; sha384; sha512; } #[link_name = "crypto"] #[abi = "cdecl"] native mod _native { type EVP_MD_CTX; type EVP_MD; fn EVP_MD_CTX_create() -> EVP_MD_CTX; fn EVP_md5() -> EVP_MD; fn EVP_sha1() -> EVP_MD; fn EVP_sha224() -> EVP_MD; fn EVP_sha256() -> EVP_MD; fn EVP_sha384() -> EVP_MD; fn EVP_sha512() -> EVP_MD; fn EVP_DigestInit(ctx: EVP_MD_CTX, typ: EVP_MD); fn EVP_DigestUpdate(ctx: EVP_MD_CTX, data: *u8, n: uint); fn EVP_DigestFinal(ctx: EVP_MD_CTX, res: *u8, n: *u32); } fn evpmd(t: hashtype) -> (_native::EVP_MD, uint) { alt t { md5. { (_native::EVP_md5(), 16u) } sha1. { (_native::EVP_sha1(), 20u) } sha224. { (_native::EVP_sha224(), 28u) } sha256. { (_native::EVP_sha256(), 32u) } sha384. { (_native::EVP_sha384(), 48u) } sha512. { (_native::EVP_sha512(), 64u) } } } fn mk_hasher(ht: hashtype) -> hasher { type hasherstate = { evp: _native::EVP_MD, ctx: _native::EVP_MD_CTX, len: uint }; obj hasher(st: hasherstate) { fn init() unsafe { _native::EVP_DigestInit(st.ctx, st.evp); } fn update(data: [u8]) unsafe { let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data); _native::EVP_DigestUpdate(st.ctx, pdata, vec::len(data)); } fn final() -> [u8] unsafe { let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, st.len); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); _native::EVP_DigestFinal(st.ctx, pres, ptr::null::<u32>()); vec::from_mut::<u8>(res) } } let ctx = _native::EVP_MD_CTX_create(); let (evp, mdlen) = evpmd(ht); let st = { evp: evp, ctx: ctx, len: mdlen }; let h = hasher(st); h.init(); ret h; } /* Function: hash Hashes the supplied input data using hash t, returning the resulting hash value */ fn hash(t: hashtype, data: [u8]) -> [u8] unsafe { let ctx = _native::EVP_MD_CTX_create(); let (evp, mdlen) = evpmd(t); let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, mdlen); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data); _native::EVP_DigestInit(ctx, evp); _native::EVP_DigestUpdate(ctx, pdata, vec::len(data)); _native::EVP_DigestFinal(ctx, pres, ptr::null::<u32>()); ret vec::from_mut::<u8>(res); } #[cfg(test)] mod tests { // Test vectors from http://www.nsrl.nist.gov/testdata/ #[test] fn test_md5() { let s0 = [0x61u8, 0x62u8, 0x63u8]; let d0 = [0x90u8, 0x01u8, 0x50u8, 0x98u8, 0x3cu8, 0xd2u8, 0x4fu8, 0xb0u8, 0xd6u8, 0x96u8, 0x3fu8, 0x7du8, 0x28u8, 0xe1u8, 0x7fu8, 0x72u8]; assert(hash(md5, s0) == d0); } #[test] fn test_sha1() { let s0 = [0x61u8, 0x62u8, 0x63u8]; let d0 = [0xa9u8, 0x99u8, 0x3eu8, 0x36u8, 0x47u8, 0x06u8, 0x81u8, 0x6au8, 0xbau8, 0x3eu8, 0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xc2u8, 0x6cu8, 0x9cu8, 0xd0u8, 0xd8u8, 0x9du8]; assert(hash(sha1, s0) == d0); } #[test] fn test_sha256() { let s0 = [0x61u8, 0x62u8, 0x63u8]; let d0 = [0xbau8, 0x78u8, 0x16u8, 0xbfu8, 0x8fu8, 0x01u8, 0xcfu8, 0xeau8, 0x41u8, 0x41u8, 0x40u8, 0xdeu8, 0x5du8, 0xaeu8, 0x22u8, 0x23u8, 0xb0u8, 0x03u8, 0x61u8, 0xa3u8, 0x96u8, 0x17u8, 0x7au8, 0x9cu8, 0xb4u8, 0x10u8, 0xffu8, 0x61u8, 0xf2u8, 0x00u8, 0x15u8, 0xadu8]; assert(hash(sha256, s0) == d0); } } fn main() { let h = mk_hasher(sha512); h.init(); h.update(str::bytes("")); log h.final(); log hash(sha512, str::bytes("")); }
pkey.rs 0 → 100644 +351 −0 Original line number Diff line number Diff line use std; import std::ptr; import std::str; import std::unsafe; import std::vec; export pkeyrole, encrypt, decrypt, sign, verify; export pkey, mk_pkey; export _native; #[link_name = "crypto"] #[abi = "cdecl"] native mod _native { type EVP_PKEY; type ANYKEY; type RSA; fn EVP_PKEY_new() -> *EVP_PKEY; fn EVP_PKEY_free(k: *EVP_PKEY); fn EVP_PKEY_assign(k: *EVP_PKEY, t: int, inner: *ANYKEY); fn EVP_PKEY_get0(k: *EVP_PKEY) -> *ANYKEY; fn i2d_PublicKey(k: *EVP_PKEY, buf: **u8) -> int; fn d2i_PublicKey(t: int, k: **EVP_PKEY, buf: **u8, len: uint) -> *EVP_PKEY; fn i2d_PrivateKey(k: *EVP_PKEY, buf: **u8) -> int; fn d2i_PrivateKey(t: int, k: **EVP_PKEY, buf: **u8, len: uint) -> *EVP_PKEY; fn RSA_generate_key(modsz: uint, e: uint, cb: *u8, cbarg: *u8) -> *RSA; fn RSA_size(k: *RSA) -> uint; fn RSA_public_encrypt(flen: uint, from: *u8, to: *u8, k: *RSA, pad: int) -> int; fn RSA_private_decrypt(flen: uint, from: *u8, to: *u8, k: *RSA, pad: int) -> int; fn RSA_sign(t: int, m: *u8, mlen: uint, sig: *u8, siglen: *uint, k: *RSA) -> int; fn RSA_verify(t: int, m: *u8, mlen: uint, sig: *u8, siglen: uint, k: *RSA) -> int; } tag pkeyparts { neither; public; both; } /* Tag: pkeyrole Represents a role an asymmetric key might be appropriate for. */ tag pkeyrole { encrypt; decrypt; sign; verify; } /* Object: pkey Represents a public key, optionally with a private key attached. */ type pkey = obj { /* Method: save_pub Returns a serialized form of the public key, suitable for load_pub(). */ fn save_pub() -> [u8]; /* Method: load_pub Loads a serialized form of the public key, as produced by save_pub(). */ fn load_pub(s: [u8]); /* Method: save_priv Returns a serialized form of the public and private keys, suitable for load_priv(). */ fn save_priv() -> [u8]; /* Method: load_priv Loads a serialized form of the public and private keys, as produced by save_priv(). */ fn load_priv(s: [u8]); /* Method: size() Returns the size of the public key modulus. */ fn size() -> uint; /* Method: gen() Generates a public/private keypair of the specified size. */ fn gen(keysz: uint); /* Method: can() Returns whether this pkey object can perform the specified role. */ fn can(role: pkeyrole) -> bool; /* Method: max_data() Returns the maximum amount of data that can be encrypted by an encrypt() call. */ fn max_data() -> uint; /* Method: encrypt() Encrypts data using OAEP padding, returning the encrypted data. The supplied data must not be larger than max_data(). */ fn encrypt(s: [u8]) -> [u8]; /* Method: decrypt() Decrypts data, expecting OAEP padding, returning the decrypted data. */ fn decrypt(s: [u8]) -> [u8]; /* Method: sign() Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(), can process an arbitrary amount of data; returns the signature. */ fn sign(s: [u8]) -> [u8]; /* Method: verify() Verifies a signature s (using OpenSSL's default scheme and sha256) on a message m. Returns true if the signature is valid, and false otherwise. */ fn verify(m: [u8], s: [u8]) -> bool; }; fn rsa_to_any(rsa: *_native::RSA) -> *_native::ANYKEY unsafe { unsafe::reinterpret_cast::<*_native::RSA, *_native::ANYKEY>(rsa) } fn any_to_rsa(anykey: *_native::ANYKEY) -> *_native::RSA unsafe { unsafe::reinterpret_cast::<*_native::ANYKEY, *_native::RSA>(anykey) } fn mk_pkey() -> pkey { type pkeystate = { mutable evp: *_native::EVP_PKEY, mutable parts: pkeyparts }; fn _tostr(st: pkeystate, f: fn@(*_native::EVP_PKEY, **u8) -> int) -> [u8] unsafe { let len = f(st.evp, ptr::null()); if len < 0 { ret []; } let s: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len as uint); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); let pps: **u8 = ptr::addr_of(ps); let r = f(st.evp, pps); let bytes = vec::slice::<u8>(s, 0u, r as uint); ret bytes; } fn _fromstr(st: pkeystate, f: fn@(int, **_native::EVP_PKEY, **u8, uint) -> *_native::EVP_PKEY, s: [u8]) unsafe { let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); let pps: **u8 = ptr::addr_of(ps); let evp: *_native::EVP_PKEY = ptr::null(); let pevp: **_native::EVP_PKEY = ptr::addr_of(evp); f(6, pevp, pps, vec::len(s)); st.evp = *pevp; } obj pkey(st: pkeystate) { fn gen(keysz: uint) unsafe { let rsa = _native::RSA_generate_key(keysz, 65537u, ptr::null(), ptr::null()); let rsa_ = rsa_to_any(rsa); // XXX: 6 == NID_rsaEncryption _native::EVP_PKEY_assign(st.evp, 6, rsa_); st.parts = both; } fn save_pub() -> [u8] { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::i2d_PublicKey(_, _); _tostr(st, f) } fn load_pub(s: [u8]) { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::d2i_PublicKey(_, _, _, _); _fromstr(st, f, s); st.parts = public; } fn save_priv() -> [u8] { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::i2d_PrivateKey(_, _); _tostr(st, f) } fn load_priv(s: [u8]) { // FIXME: https://github.com/graydon/rust/issues/1281 let f = bind _native::d2i_PrivateKey(_, _, _, _); _fromstr(st, f, s); st.parts = both; } fn size() -> uint { _native::RSA_size(any_to_rsa(_native::EVP_PKEY_get0(st.evp))) } fn can(r: pkeyrole) -> bool { alt r { encrypt. { st.parts != neither } verify. { st.parts != neither } decrypt. { st.parts == both } sign. { st.parts == both } } } fn max_data() -> uint unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); // 41 comes from RSA_public_encrypt(3) for OAEP ret len - 41u; } fn encrypt(s: [u8]) -> [u8] unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); // 41 comes from RSA_public_encrypt(3) for OAEP assert(vec::len(s) < _native::RSA_size(rsa) - 41u); let r: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len + 1u); let pr: *u8 = vec::unsafe::to_ptr::<u8>(r); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); // XXX: 4 == RSA_PKCS1_OAEP_PADDING let rv = _native::RSA_public_encrypt(vec::len(s), ps, pr, rsa, 4); if rv < 0 { ret []; } ret vec::slice::<u8>(r, 0u, rv as uint); } fn decrypt(s: [u8]) -> [u8] unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); assert(vec::len(s) == _native::RSA_size(rsa)); let r: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len + 1u); let pr: *u8 = vec::unsafe::to_ptr::<u8>(r); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); // XXX: 4 == RSA_PKCS1_OAEP_PADDING let rv = _native::RSA_private_decrypt(vec::len(s), ps, pr, rsa, 4); if rv < 0 { ret []; } ret vec::slice::<u8>(r, 0u, rv as uint); } fn sign(s: [u8]) -> [u8] unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let len = _native::RSA_size(rsa); let r: [mutable u8] = vec::init_elt_mut::<u8>(0u8, len + 1u); let pr: *u8 = vec::unsafe::to_ptr::<u8>(r); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); let plen: *uint = ptr::addr_of(len); // XXX: 672 == NID_sha256 let rv = _native::RSA_sign(672, ps, vec::len(s), pr, plen, rsa); if rv < 0 { ret []; } ret vec::slice::<u8>(r, 0u, *plen as uint); } fn verify(m: [u8], s: [u8]) -> bool unsafe { let rsa = any_to_rsa(_native::EVP_PKEY_get0(st.evp)); let pm: *u8 = vec::unsafe::to_ptr::<u8>(m); let ps: *u8 = vec::unsafe::to_ptr::<u8>(s); // XXX: 672 == NID_sha256 let rv = _native::RSA_verify(672, pm, vec::len(m), ps, vec::len(s), rsa); ret rv == 1; } } let st = { mutable evp: _native::EVP_PKEY_new(), mutable parts: neither }; let p = pkey(st); ret p; } #[cfg(test)] mod tests { #[test] fn test_gen_pub() { let k0 = mk_pkey(); let k1 = mk_pkey(); k0.gen(512u); k1.load_pub(k0.save_pub()); assert(k0.save_pub() == k1.save_pub()); assert(k0.size() == k1.size()); assert(k0.can(encrypt)); assert(k0.can(decrypt)); assert(k0.can(verify)); assert(k0.can(sign)); assert(k1.can(encrypt)); assert(!k1.can(decrypt)); assert(k1.can(verify)); assert(!k1.can(sign)); } #[test] fn test_gen_priv() { let k0 = mk_pkey(); let k1 = mk_pkey(); k0.gen(512u); k1.load_priv(k0.save_priv()); assert(k0.save_priv() == k1.save_priv()); assert(k0.size() == k1.size()); assert(k0.can(encrypt)); assert(k0.can(decrypt)); assert(k0.can(verify)); assert(k0.can(sign)); assert(k1.can(encrypt)); assert(k1.can(decrypt)); assert(k1.can(verify)); assert(k1.can(sign)); } #[test] fn test_encrypt() { let k0 = mk_pkey(); let k1 = mk_pkey(); let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; k0.gen(512u); k1.load_pub(k0.save_pub()); let emsg = k1.encrypt(msg); let dmsg = k0.decrypt(emsg); assert(msg == dmsg); } #[test] fn test_sign() { let k0 = mk_pkey(); let k1 = mk_pkey(); let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; k0.gen(512u); k1.load_pub(k0.save_pub()); let sig = k0.sign(msg); let rv = k1.verify(msg, sig); assert(rv == true); } }
symm.rs 0 → 100644 +198 −0 Original line number Diff line number Diff line use std; import std::ptr; import std::str; import std::vec; export crypter; export cryptermode; export encryptmode, decryptmode; export cryptertype; export aes_256_ecb, aes_256_cbc; export mk_crypter; export encrypt, decrypt; export _native; #[link_name = "crypto"] #[abi = "cdecl"] native mod _native { type EVP_CIPHER_CTX; type EVP_CIPHER; fn EVP_CIPHER_CTX_new() -> EVP_CIPHER_CTX; fn EVP_CIPHER_CTX_set_padding(ctx: EVP_CIPHER_CTX, padding: int); fn EVP_aes_128_ecb() -> EVP_CIPHER; fn EVP_aes_128_cbc() -> EVP_CIPHER; fn EVP_aes_192_ecb() -> EVP_CIPHER; fn EVP_aes_192_cbc() -> EVP_CIPHER; fn EVP_aes_256_ecb() -> EVP_CIPHER; fn EVP_aes_256_cbc() -> EVP_CIPHER; fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER, key: *u8, iv: *u8, mode: int); fn EVP_CipherUpdate(ctx: EVP_CIPHER_CTX, outbuf: *u8, outlen: *u32, inbuf: *u8, inlen: u32); fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *u8, len: *u32); } /* Object: crypter Represents a symmetric cipher context. */ type crypter = obj { /* Method: pad Enables or disables padding. If padding is disabled, total amount of data encrypted must be a multiple of block size. */ fn pad(padding: bool); /* Method: init Initializes this crypter. */ fn init(mode: cryptermode, key: [u8], iv: [u8]); /* Method: update Update this crypter with more data to encrypt or decrypt. Returns encrypted or decrypted bytes. */ fn update(data: [u8]) -> [u8]; /* Method: final Finish crypting. Returns the remaining partial block of output, if any. */ fn final() -> [u8]; }; tag cryptermode { encryptmode; decryptmode; } tag cryptertype { aes_256_ecb; aes_256_cbc; } fn evpc(t: cryptertype) -> (_native::EVP_CIPHER, uint, uint) { alt t { aes_256_ecb. { (_native::EVP_aes_256_ecb(), 32u, 16u) } aes_256_cbc. { (_native::EVP_aes_256_cbc(), 32u, 16u) } } } fn mk_crypter(t: cryptertype) -> crypter { type crypterstate = { evp: _native::EVP_CIPHER, ctx: _native::EVP_CIPHER_CTX, keylen: uint, blocksize: uint }; obj crypter(st: crypterstate) { fn pad(padding: bool) { let v = padding ? 1 : 0; _native::EVP_CIPHER_CTX_set_padding(st.ctx, v); } fn init (mode: cryptermode, key: [u8], iv: [u8]) unsafe { let m = alt mode { encryptmode. { 1 } decryptmode. { 0 } }; assert(vec::len(key) == st.keylen); let pkey: *u8 = vec::unsafe::to_ptr::<u8>(key); let piv: *u8 = vec::unsafe::to_ptr::<u8>(iv); _native::EVP_CipherInit(st.ctx, st.evp, pkey, piv, m); } fn update(data: [u8]) -> [u8] unsafe { let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data); let datalen: u32 = vec::len(data) as u32; let reslen: u32 = datalen + (st.blocksize as u32); let preslen: *u32 = ptr::addr_of(reslen); let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, reslen as uint); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); _native::EVP_CipherUpdate(st.ctx, pres, preslen, pdata, datalen); ret vec::slice::<u8>(res, 0u, *preslen as uint); } fn final() -> [u8] unsafe { let reslen: u32 = st.blocksize as u32; let preslen: *u32 = ptr::addr_of(reslen); let res: [mutable u8] = vec::init_elt_mut::<u8>(0u8, reslen as uint); let pres: *u8 = vec::unsafe::to_ptr::<u8>(res); _native::EVP_CipherFinal(st.ctx, pres, preslen); ret vec::slice::<u8>(res, 0u, *preslen as uint); } } let ctx = _native::EVP_CIPHER_CTX_new(); let (evp, keylen, blocksz) = evpc(t); let st = { evp: evp, ctx: ctx, keylen: keylen, blocksize: blocksz }; let h = crypter(st); ret h; } /* Function: encrypt Encrypts data, using the specified crypter type in encrypt mode with the specified key and iv; returns the resulting (encrypted) data. */ fn encrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] { let c = mk_crypter(t); c.init(encryptmode, key, iv); let r = c.update(data); let rest = c.final(); ret r + rest; } /* Function: decrypt Decrypts data, using the specified crypter type in decrypt mode with the specified key and iv; returns the resulting (decrypted) data. */ fn decrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] { let c = mk_crypter(t); c.init(decryptmode, key, iv); let r = c.update(data); let rest = c.final(); ret r + rest; } #[cfg(test)] mod tests { // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf #[test] fn test_aes_256_ecb() { let k0 = [ 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0au8, 0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8, 0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8, 0x16u8, 0x17u8, 0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8 ]; let p0 = [ 0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8, 0x88u8, 0x99u8, 0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8 ]; let c0 = [ 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8 ]; let c = mk_crypter(aes_256_ecb); c.init(encryptmode, k0, []); c.pad(false); let r0 = c.update(p0) + c.final(); assert(r0 == c0); c.init(decryptmode, k0, []); c.pad(false); let p1 = c.update(r0) + c.final(); assert(p1 == p0); } }