snowbridge_amcl/
gcm.rs

1/*
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements.  See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership.  The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"); you may not use this file except in compliance
8with the License.  You may obtain a copy of the License at
9
10  http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied.  See the License for the
16specific language governing permissions and limitations
17under the License.
18*/
19
20const GCM_NB: usize = 4;
21const GCM_ACCEPTING_HEADER: usize = 0;
22const GCM_ACCEPTING_CIPHER: usize = 1;
23const GCM_NOT_ACCEPTING_MORE: usize = 2;
24const GCM_FINISHED: usize = 3;
25
26use crate::aes;
27use crate::aes::AES;
28
29pub struct GCM {
30    table: [[u32; 4]; 128],
31    statex: [u8; 16],
32    y_0: [u8; 16],
33    //  counter: usize,
34    lena: [u32; 2],
35    lenc: [u32; 2],
36    status: usize,
37    a: AES,
38}
39
40impl GCM {
41    fn pack(b: [u8; 4]) -> u32 {
42        /* pack bytes into a 32-bit Word */
43        return ((((b[0]) & 0xff) as u32) << 24)
44            | ((((b[1]) & 0xff) as u32) << 16)
45            | ((((b[2]) & 0xff) as u32) << 8)
46            | (((b[3]) & 0xff) as u32);
47    }
48
49    fn unpack(a: u32) -> [u8; 4] {
50        /* unpack bytes from a word */
51        let b: [u8; 4] = [
52            ((a >> 24) & 0xff) as u8,
53            ((a >> 16) & 0xff) as u8,
54            ((a >> 8) & 0xff) as u8,
55            (a & 0xff) as u8,
56        ];
57        return b;
58    }
59
60    fn precompute(&mut self, h: &[u8]) {
61        let mut b: [u8; 4] = [0; 4];
62        let mut j = 0;
63        for i in 0..GCM_NB {
64            b[0] = h[j];
65            b[1] = h[j + 1];
66            b[2] = h[j + 2];
67            b[3] = h[j + 3];
68            self.table[0][i] = GCM::pack(b);
69            j += 4;
70        }
71        for i in 1..128 {
72            let mut c: u32 = 0;
73            for j in 0..GCM_NB {
74                self.table[i][j] = c | (self.table[i - 1][j]) >> 1;
75                c = self.table[i - 1][j] << 31;
76            }
77            if c != 0 {
78                self.table[i][0] ^= 0xE1000000
79            } /* irreducible polynomial */
80        }
81    }
82
83    fn gf2mul(&mut self) {
84        /* gf2m mul - Z=H*X mod 2^128 */
85        let mut p: [u32; 4] = [0; 4];
86
87        for i in 0..4 {
88            p[i] = 0
89        }
90        let mut j: usize = 8;
91        let mut m = 0;
92        for i in 0..128 {
93            j -= 1;
94            let mut c = ((self.statex[m] >> j) & 1) as u32;
95            c = (!c) + 1;
96            for k in 0..GCM_NB {
97                p[k] ^= self.table[i][k] & c
98            }
99            if j == 0 {
100                j = 8;
101                m += 1;
102                if m == 16 {
103                    break;
104                }
105            }
106        }
107        j = 0;
108        for i in 0..GCM_NB {
109            let b = GCM::unpack(p[i]);
110            self.statex[j] = b[0];
111            self.statex[j + 1] = b[1];
112            self.statex[j + 2] = b[2];
113            self.statex[j + 3] = b[3];
114            j += 4;
115        }
116    }
117
118    fn wrap(&mut self) {
119        /* Finish off GHASH */
120        let mut f: [u32; 4] = [0; 4];
121        let mut el: [u8; 16] = [0; 16];
122
123        /* convert lengths from bytes to bits */
124        f[0] = (self.lena[0] << 3) | (self.lena[1] & 0xE0000000) >> 29;
125        f[1] = self.lena[1] << 3;
126        f[2] = (self.lenc[0] << 3) | (self.lenc[1] & 0xE0000000) >> 29;
127        f[3] = self.lenc[1] << 3;
128        let mut j = 0;
129        for i in 0..GCM_NB {
130            let b = GCM::unpack(f[i]);
131            el[j] = b[0];
132            el[j + 1] = b[1];
133            el[j + 2] = b[2];
134            el[j + 3] = b[3];
135            j += 4;
136        }
137        for i in 0..16 {
138            self.statex[i] ^= el[i]
139        }
140        self.gf2mul();
141    }
142
143    fn ghash(&mut self, plain: &[u8], len: usize) -> bool {
144        if self.status == GCM_ACCEPTING_HEADER {
145            self.status = GCM_ACCEPTING_CIPHER
146        }
147        if self.status != GCM_ACCEPTING_CIPHER {
148            return false;
149        }
150
151        let mut j = 0;
152        while j < len {
153            for i in 0..16 {
154                if j >= len {
155                    break;
156                }
157                self.statex[i] ^= plain[j];
158                j += 1;
159                self.lenc[1] += 1;
160                if self.lenc[1] == 0 {
161                    self.lenc[0] += 1
162                }
163            }
164            self.gf2mul();
165        }
166        if len % 16 != 0 {
167            self.status = GCM_NOT_ACCEPTING_MORE
168        }
169        return true;
170    }
171
172    /* Initialize GCM mode */
173    pub fn init(&mut self, nk: usize, key: &[u8], niv: usize, iv: &[u8]) {
174        /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */
175        let mut h: [u8; 16] = [0; 16];
176
177        for i in 0..16 {
178            h[i] = 0;
179            self.statex[i] = 0
180        }
181
182        self.a = AES::new();
183
184        self.a.init(aes::ECB, nk, key, None);
185        self.a.ecb_encrypt(&mut h); /* E(K,0) */
186        self.precompute(&h);
187
188        self.lena[0] = 0;
189        self.lenc[0] = 0;
190        self.lena[1] = 0;
191        self.lenc[1] = 0;
192        if niv == 12 {
193            for i in 0..12 {
194                self.a.f[i] = iv[i]
195            }
196            let b = GCM::unpack(1);
197            self.a.f[12] = b[0];
198            self.a.f[13] = b[1];
199            self.a.f[14] = b[2];
200            self.a.f[15] = b[3]; /* initialise IV */
201            for i in 0..16 {
202                self.y_0[i] = self.a.f[i]
203            }
204        } else {
205            self.status = GCM_ACCEPTING_CIPHER;
206            self.ghash(iv, niv); /* GHASH(H,0,IV) */
207            self.wrap();
208            for i in 0..16 {
209                self.a.f[i] = self.statex[i];
210                self.y_0[i] = self.a.f[i];
211                self.statex[i] = 0
212            }
213            self.lena[0] = 0;
214            self.lenc[0] = 0;
215            self.lena[1] = 0;
216            self.lenc[1] = 0;
217        }
218        self.status = GCM_ACCEPTING_HEADER;
219    }
220
221    pub fn new() -> GCM {
222        GCM {
223            table: [[0; 4]; 128],
224            statex: [0; 16],
225            y_0: [0; 16],
226            //counter:0,
227            lena: [0; 2],
228            lenc: [0; 2],
229            status: 0,
230            a: AES::new(),
231        }
232    }
233
234    /* Add Header data - included but not encrypted */
235    pub fn add_header(&mut self, header: &[u8], len: usize) -> bool {
236        /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */
237        if self.status != GCM_ACCEPTING_HEADER {
238            return false;
239        }
240        let mut j = 0;
241        while j < len {
242            for i in 0..16 {
243                if j >= len {
244                    break;
245                }
246                self.statex[i] ^= header[j];
247                j += 1;
248                self.lena[1] += 1;
249                if self.lena[1] == 0 {
250                    self.lena[0] += 1
251                }
252            }
253            self.gf2mul();
254        }
255        if len % 16 != 0 {
256            self.status = GCM_ACCEPTING_CIPHER
257        }
258        return true;
259    }
260
261    /* Add Plaintext - included and encrypted */
262    pub fn add_plain(&mut self, cipher: &mut [u8], plain: &[u8], len: usize) -> bool {
263        let mut cb: [u8; 16] = [0; 16];
264        let mut b: [u8; 4] = [0; 4];
265
266        let mut counter: u32;
267        if self.status == GCM_ACCEPTING_HEADER {
268            self.status = GCM_ACCEPTING_CIPHER
269        }
270        if self.status != GCM_ACCEPTING_CIPHER {
271            return false;
272        }
273
274        let mut j = 0;
275        while j < len {
276            b[0] = self.a.f[12];
277            b[1] = self.a.f[13];
278            b[2] = self.a.f[14];
279            b[3] = self.a.f[15];
280            counter = GCM::pack(b);
281            counter += 1;
282            b = GCM::unpack(counter);
283            self.a.f[12] = b[0];
284            self.a.f[13] = b[1];
285            self.a.f[14] = b[2];
286            self.a.f[15] = b[3]; /* increment counter */
287            for i in 0..16 {
288                cb[i] = self.a.f[i]
289            }
290            self.a.ecb_encrypt(&mut cb); /* encrypt it  */
291
292            for i in 0..16 {
293                if j >= len {
294                    break;
295                }
296                cipher[j] = plain[j] ^ cb[i];
297                self.statex[i] ^= cipher[j];
298                j += 1;
299                self.lenc[1] += 1;
300                if self.lenc[1] == 0 {
301                    self.lenc[0] += 1
302                }
303            }
304            self.gf2mul()
305        }
306        if len % 16 != 0 {
307            self.status = GCM_NOT_ACCEPTING_MORE
308        }
309        return true;
310    }
311
312    /* Add Ciphertext - decrypts to plaintext */
313    pub fn add_cipher(&mut self, plain: &mut [u8], cipher: &[u8], len: usize) -> bool {
314        let mut cb: [u8; 16] = [0; 16];
315        let mut b: [u8; 4] = [0; 4];
316
317        let mut counter: u32;
318
319        if self.status == GCM_ACCEPTING_HEADER {
320            self.status = GCM_ACCEPTING_CIPHER
321        }
322        if self.status != GCM_ACCEPTING_CIPHER {
323            return false;
324        }
325
326        let mut j = 0;
327        while j < len {
328            b[0] = self.a.f[12];
329            b[1] = self.a.f[13];
330            b[2] = self.a.f[14];
331            b[3] = self.a.f[15];
332            counter = GCM::pack(b);
333            counter += 1;
334            b = GCM::unpack(counter);
335            self.a.f[12] = b[0];
336            self.a.f[13] = b[1];
337            self.a.f[14] = b[2];
338            self.a.f[15] = b[3]; /* increment counter */
339            for i in 0..16 {
340                cb[i] = self.a.f[i]
341            }
342            self.a.ecb_encrypt(&mut cb); /* encrypt it  */
343            for i in 0..16 {
344                if j >= len {
345                    break;
346                }
347                let oc = cipher[j];
348                plain[j] = cipher[j] ^ cb[i];
349                self.statex[i] ^= oc;
350                j += 1;
351                self.lenc[1] += 1;
352                if self.lenc[1] == 0 {
353                    self.lenc[0] += 1
354                }
355            }
356            self.gf2mul()
357        }
358        if len % 16 != 0 {
359            self.status = GCM_NOT_ACCEPTING_MORE
360        }
361        return true;
362    }
363
364    /* Finish and extract Tag */
365    pub fn finish(&mut self, extract: bool) -> [u8; 16] {
366        /* Finish off GHASH and extract tag (MAC) */
367        let mut tag: [u8; 16] = [0; 16];
368
369        self.wrap();
370        /* extract tag */
371        if extract {
372            self.a.ecb_encrypt(&mut (self.y_0)); /* E(K,Y0) */
373            for i in 0..16 {
374                self.y_0[i] ^= self.statex[i]
375            }
376            for i in 0..16 {
377                tag[i] = self.y_0[i];
378                self.y_0[i] = 0;
379                self.statex[i] = 0
380            }
381        }
382        self.status = GCM_FINISHED;
383        self.a.end();
384        return tag;
385    }
386
387    pub fn hex2bytes(hex: &[u8], bin: &mut [u8]) {
388        let len = hex.len();
389
390        for i in 0..len / 2 {
391            let mut v: u8;
392            let mut c = hex[2 * i];
393            if c >= b'0' && c <= b'9' {
394                v = c - b'0';
395            } else if c >= b'A' && c <= b'F' {
396                v = c - b'A' + 10;
397            } else if c >= b'a' && c <= b'f' {
398                v = c - b'a' + 10;
399            } else {
400                v = 0;
401            }
402            v <<= 4;
403            c = hex[2 * i + 1];
404            if c >= b'0' && c <= b'9' {
405                v += c - b'0';
406            } else if c >= b'A' && c <= b'F' {
407                v += c - b'A' + 10;
408            } else if c >= b'a' && c <= b'f' {
409                v += c - b'a' + 10;
410            } else {
411                v = 0;
412            }
413            bin[i] = v;
414        }
415    }
416}
417/*
418fn main()
419{
420    let kt=b"feffe9928665731c6d6a8f9467308308";
421    let mt=b"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
422    let ht=b"feedfacedeadbeeffeedfacedeadbeefabaddad2";
423    let nt=b"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b";
424// Tag should be 619cc5aefffe0bfa462af43c1699d050
425
426    let mut gcm=GCM::new();
427
428    let len=mt.len()/2;
429    let lenh=ht.len()/2;
430    let lenk=kt.len()/2;
431    let leniv=nt.len()/2;
432
433    //let mut t:[u8;16]=[0;16]; // Tag
434    let mut k:[u8;16]=[0;16];   // AES Key
435    let mut h:[u8;64]=[0;64];   // Header - to be included in Authentication, but not encrypted
436    let mut n:[u8;100]=[0;100]; // IV - Initialisation vector
437    let mut m:[u8;100]=[0;100]; // Plaintext to be encrypted/authenticated
438    let mut c:[u8;100]=[0;100]; // Ciphertext
439    let mut p:[u8;100]=[0;100]; // Recovered Plaintext
440
441    GCM::hex2bytes(mt,&mut m);
442    GCM::hex2bytes(ht,&mut h);
443    GCM::hex2bytes(kt,&mut k);
444    GCM::hex2bytes(nt,&mut n);
445
446     println!("Plaintext=");
447    for i in 0..len {print!("{:02x}",m[i])}
448    println!("");
449
450    gcm.init(lenk,&k,leniv,&n);
451
452    gcm.add_header(&h,lenh);
453    gcm.add_plain(&mut c,&m,len);
454    let mut t=gcm.finish(true);
455
456     println!("Ciphertext=");
457    for i in 0..len {print!("{:02x}",c[i])}
458    println!("");
459
460     println!("Tag=");
461    for i in 0..16 {print!("{:02x}",t[i])}
462    println!("");
463
464    gcm.init(lenk,&k,leniv,&n);
465
466    gcm.add_header(&h,lenh);
467    gcm.add_cipher(&mut p,&c,len);
468    t=gcm.finish(true);
469
470     println!("Plaintext=");
471    for i in 0..len {print!("{:02x}",p[i])}
472    println!("");
473
474    println!("Tag=");
475    for i in 0..16 {print!("{:02x}",t[i])}
476    println!("");
477
478}
479*/