rsa_public_encrypt_pkcs1/
lib.rs

1extern crate num;
2extern crate simple_asn1;
3extern crate rand;
4
5use num::bigint::{BigInt};
6use simple_asn1::{from_der, ASN1Block};
7use rand::Rng;
8
9fn find_bitstrings(asns: Vec<ASN1Block>, mut result: &mut Vec<Vec<u8>>) {
10    for asn in asns.iter() {
11        match asn {
12            ASN1Block::BitString(_, _, bytes) => result.push(bytes.to_vec()),
13            ASN1Block::Sequence(_, blocks) => find_bitstrings(blocks.to_vec(), &mut result),
14            _ => (),
15        }
16    }
17}
18
19pub fn encrypt(der_pubkey: &[u8], message: &[u8]) -> Result<Vec<u8>, String> {
20    // Outer ASN.1 encodes 1.2.840.113549.1.1 OID and wraps a bitstring, find it
21    let asns: Vec<ASN1Block> = from_der(&der_pubkey).map_err(|err| err.to_string())?;
22    let mut result: Vec<Vec<u8>> = vec![];
23    find_bitstrings(asns, &mut result);
24    if result.len() == 0 {
25        return Err("ASN.1 BitString not found in DER encoding of public key".to_string());
26    }
27
28    let inner_asn: Vec<ASN1Block> = from_der(&result[0]).map_err(|err| err.to_string())?;
29    let (n, e) =
30    match &inner_asn[0] {
31        ASN1Block::Sequence(_, blocks) => {
32            if blocks.len() != 2 {
33                return Err("ASN.1 sequence bad length, expected exactly two blocks in inner Sequence".to_string());
34            }
35
36            let n = match &blocks[0] {
37                ASN1Block::Integer(_, n) => n,
38                _ => return Err("ASN.1 Integer modulus not found".to_string()),
39            };
40
41            let e = match &blocks[1] {
42                ASN1Block::Integer(_, e) => e,
43                _ => return Err("ASN.1 Integer exponent not found".to_string()),
44            };
45            (n, e)
46
47        },
48        _ => return Err("ASN.1 Sequence not found".to_string()),
49    };
50
51    // PKCS#1 padding https://tools.ietf.org/html/rfc8017#section-7.2.1 RSAES-PKCS1-V1_5-ENCRYPT ((n, e), M)
52    let k = (n.bits() / 8) as usize; // bytes in modulus
53    // TODO: is it possible this will be a non-integral value, do we need to handle this case?
54    //if k != 1024/8 { panic!("expected 1024-bit modulus"); }
55
56    /* Steps:
57     *
58     *  1.  Length checking: If mLen > k - 11, output "message too long"
59     *     and stop.
60     */
61    if message.len() > k - 11 {
62        return Err("PKCS#1 error: message too long".to_string());
63    }
64
65    /*
66     * 2.  EME-PKCS1-v1_5 encoding:
67     *
68     *     a.  Generate an octet string PS of length k - mLen - 3
69     *         consisting of pseudo-randomly generated nonzero octets.
70     *         The length of PS will be at least eight octets.
71     */
72    let mut padding = vec![1; k - message.len() - 3];
73    let mut i = 0;
74    while i < padding.len() {
75        padding[i] = rand::thread_rng().gen_range(1..255);
76        i += 1;
77    }
78
79    /* b.  Concatenate PS, the message M, and other padding to form
80     *     an encoded message EM of length k octets as
81     *
82     *            EM = 0x00 || 0x02 || PS || 0x00 || M.
83     */
84    let mut encoded_m = vec![0x00, 0x02];
85    encoded_m.append(&mut padding.to_vec());
86    encoded_m.append(&mut vec![0x00]);
87    encoded_m.extend_from_slice(&message);
88
89    /* 3.  RSA encryption:
90     *
91     *     a.  Convert the encoded message EM to an integer message
92     *         representative m (see Section 4.2):
93     *
94     *           m = OS2IP (EM).
95     */
96    // OS2IP https://tools.ietf.org/html/rfc8017#section-4.2
97    let m = BigInt::from_bytes_be(num::bigint::Sign::Plus, &encoded_m);
98
99    /*     b.  Apply the RSAEP encryption primitive (Section 5.1.1) to
100     *         the RSA public key (n, e) and the message representative m
101     *         to produce an integer ciphertext representative c:
102     *
103     *            c = RSAEP ((n, e), m).
104     */
105    // https://tools.ietf.org/html/rfc8017#section-5.1.1
106    /* 1.  If the message representative m is not between 0 and n - 1,
107     *     output "message representative out of range" and stop.
108     */
109    if m.sign() != num::bigint::Sign::Plus || m > n - 1 {
110        return Err("RSA error: message representative out of range".to_string());
111    }
112
113    // 2.  Let c = m^e mod n.
114    let ciphertext_bigint = m.modpow(e, n);
115
116    /*     c.  Convert the ciphertext representative c to a ciphertext C
117     *         of length k octets (see Section 4.1):
118     *
119     *            C = I2OSP (c, k).
120     */
121    // 4.1. I2OSP https://tools.ietf.org/html/rfc8017#section-4.1
122    let (_sign, ciphertext) = ciphertext_bigint.to_bytes_be();
123
124    return Ok(ciphertext);
125}
126
127
128#[cfg(test)]
129mod tests {
130    use crate::encrypt;
131    #[test]
132    fn it_works() {
133        assert_eq!(2 + 2, 4);
134        assert_eq!(encrypt(&[], &[]), Err("Encountered an empty buffer decoding ASN1 block.".to_string()));
135        //assert_eq!(encrypt(&[1], &[]), Err("Encountered an empty buffer decoding ASN1 block.".to_string())); // simple_asn1 panics TODO
136        // TODO: test more errors
137
138        /*
139     $ openssl asn1parse -inform DER -in /tmp/d
140    0:d=0  hl=3 l= 159 cons: SEQUENCE
141    3:d=1  hl=2 l=  13 cons: SEQUENCE
142    5:d=2  hl=2 l=   9 prim: OBJECT            :rsaEncryption
143   16:d=2  hl=2 l=   0 prim: NULL
144   18:d=1  hl=3 l= 141 prim: BIT STRING
145   */
146        // 1024-bit (128-byte) public key, encoded in ASN.1 DER
147        let pk = [48, 129, 159, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 129, 141, 0, 48, 129, 137, 2, 129, 129, 0, 149, 92, 126, 71, 214, 186, 100, 139, 40, 104, 65, 254, 200, 105, 71, 66, 241, 84, 172, 206, 206, 217, 49, 214, 16, 50, 6, 234, 97, 21, 170, 139, 234, 88, 220, 105, 27, 115, 56, 103, 53, 234, 84, 255, 129, 147, 41, 146, 68, 39, 120, 208, 141, 142, 39, 242, 182, 97, 4, 204, 236, 190, 104, 101, 234, 46, 71, 248, 55, 88, 213, 56, 145, 154, 142, 184, 144, 55, 105, 241, 179, 205, 174, 107, 40, 77, 46, 201, 197, 51, 20, 246, 95, 207, 227, 5, 210, 42, 107, 135, 219, 126, 207, 216, 181, 2, 130, 57, 203, 239, 232, 68, 220, 131, 211, 86, 168, 125, 193, 91, 148, 153, 109, 76, 109, 50, 2, 139, 2, 3, 1, 0, 1];
148
149        // Raw RSA PKCS#1 encryption requires message isn't much longer than the key size (no hash)
150        assert_eq!(encrypt(&pk, &[0; 128]), Err("PKCS#1 error: message too long".to_string()));
151        assert_eq!(encrypt(&pk, &[0; 128-1]), Err("PKCS#1 error: message too long".to_string()));
152        assert_eq!(encrypt(&pk, &[0; 128-2]), Err("PKCS#1 error: message too long".to_string()));
153        assert_eq!(encrypt(&pk, &[0; 128-10]), Err("PKCS#1 error: message too long".to_string()));
154
155        // Successful encryption
156        // TODO: fix random bytes and add result test vectors
157        assert_eq!(encrypt(&pk, &[]).is_ok(), true);
158        assert_eq!(encrypt(&pk, &[1, 2, 3, 4]).is_ok(), true);
159        assert_eq!(encrypt(&pk, &[0; 128-11]).is_ok(), true);
160    }
161}
162
163