| 1 | module blowfish |
| 2 | |
| 3 | // expand_key performs a key expansion on the given Blowfish cipher. |
| 4 | @[direct_array_access] |
| 5 | pub fn expand_key(key []u8, mut bf Blowfish) { |
| 6 | mut j := 0 |
| 7 | for i := 0; i < 18; i++ { |
| 8 | mut d := u32(0) |
| 9 | for k := 0; k < 4; k++ { |
| 10 | d = d << 8 | u32(key[j]) |
| 11 | j++ |
| 12 | if j >= key.len { |
| 13 | j = 0 |
| 14 | } |
| 15 | } |
| 16 | bf.p[i] ^= d |
| 17 | } |
| 18 | |
| 19 | mut l := u32(0) |
| 20 | mut r := u32(0) |
| 21 | for i := 0; i < 18; i += 2 { |
| 22 | l, r = setup_tables(l, r, mut bf) |
| 23 | bf.p[i], bf.p[i + 1] = l, r |
| 24 | } |
| 25 | |
| 26 | for i := 0; i < 256; i += 2 { |
| 27 | l, r = setup_tables(l, r, mut bf) |
| 28 | bf.s[0][i], bf.s[0][i + 1] = l, r |
| 29 | } |
| 30 | for i := 0; i < 256; i += 2 { |
| 31 | l, r = setup_tables(l, r, mut bf) |
| 32 | bf.s[1][i], bf.s[1][i + 1] = l, r |
| 33 | } |
| 34 | for i := 0; i < 256; i += 2 { |
| 35 | l, r = setup_tables(l, r, mut bf) |
| 36 | bf.s[2][i], bf.s[2][i + 1] = l, r |
| 37 | } |
| 38 | for i := 0; i < 256; i += 2 { |
| 39 | l, r = setup_tables(l, r, mut bf) |
| 40 | bf.s[3][i], bf.s[3][i + 1] = l, r |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | // expand_key_with_salt using salt to expand the key. |
| 45 | @[direct_array_access] |
| 46 | pub fn expand_key_with_salt(key []u8, salt []u8, mut bf Blowfish) { |
| 47 | mut j := 0 |
| 48 | for i := 0; i < 18; i++ { |
| 49 | bf.p[i] ^= get_next_word(key, &j) |
| 50 | } |
| 51 | |
| 52 | j = 0 |
| 53 | |
| 54 | mut l := u32(0) |
| 55 | mut r := u32(0) |
| 56 | for i := 0; i < 18; i += 2 { |
| 57 | l ^= get_next_word(salt, &j) |
| 58 | r ^= get_next_word(salt, &j) |
| 59 | l, r = setup_tables(l, r, mut bf) |
| 60 | bf.p[i], bf.p[i + 1] = l, r |
| 61 | } |
| 62 | |
| 63 | for i := 0; i < 256; i += 2 { |
| 64 | l ^= get_next_word(salt, &j) |
| 65 | r ^= get_next_word(salt, &j) |
| 66 | l, r = setup_tables(l, r, mut bf) |
| 67 | bf.s[0][i], bf.s[0][i + 1] = l, r |
| 68 | } |
| 69 | for i := 0; i < 256; i += 2 { |
| 70 | l ^= get_next_word(salt, &j) |
| 71 | r ^= get_next_word(salt, &j) |
| 72 | l, r = setup_tables(l, r, mut bf) |
| 73 | bf.s[1][i], bf.s[1][i + 1] = l, r |
| 74 | } |
| 75 | for i := 0; i < 256; i += 2 { |
| 76 | l ^= get_next_word(salt, &j) |
| 77 | r ^= get_next_word(salt, &j) |
| 78 | l, r = setup_tables(l, r, mut bf) |
| 79 | bf.s[2][i], bf.s[2][i + 1] = l, r |
| 80 | } |
| 81 | for i := 0; i < 256; i += 2 { |
| 82 | l ^= get_next_word(salt, &j) |
| 83 | r ^= get_next_word(salt, &j) |
| 84 | l, r = setup_tables(l, r, mut bf) |
| 85 | bf.s[3][i], bf.s[3][i + 1] = l, r |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // setup_tables sets up the Blowfish cipher's pi and substitution tables. |
| 90 | @[direct_array_access] |
| 91 | fn setup_tables(l u32, r u32, mut bf Blowfish) (u32, u32) { |
| 92 | mut xl := l |
| 93 | mut xr := r |
| 94 | xl ^= bf.p[0] |
| 95 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[1] |
| 96 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[2] |
| 97 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[3] |
| 98 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[4] |
| 99 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[5] |
| 100 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[6] |
| 101 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[7] |
| 102 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[8] |
| 103 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[9] |
| 104 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[10] |
| 105 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[11] |
| 106 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[12] |
| 107 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[13] |
| 108 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[14] |
| 109 | xr ^= ((bf.s[0][u8(xl >> 24)] + bf.s[1][u8(xl >> 16)]) ^ bf.s[2][u8(xl >> 8)]) + bf.s[3][u8(xl)] ^ bf.p[15] |
| 110 | xl ^= ((bf.s[0][u8(xr >> 24)] + bf.s[1][u8(xr >> 16)]) ^ bf.s[2][u8(xr >> 8)]) + bf.s[3][u8(xr)] ^ bf.p[16] |
| 111 | xr ^= bf.p[17] |
| 112 | return xr, xl |
| 113 | } |
| 114 | |
| 115 | // get_next_word returns the next big-endian u32 value from the byte |
| 116 | // slice at the given position in a circular manner, updating the position. |
| 117 | @[direct_array_access] |
| 118 | fn get_next_word(b []u8, pos &int) u32 { |
| 119 | mut w := u32(0) |
| 120 | mut j := 0 |
| 121 | unsafe { |
| 122 | j = *pos |
| 123 | } |
| 124 | for i := 0; i < 4; i++ { |
| 125 | w = w << 8 | u32(b[j]) |
| 126 | j++ |
| 127 | if j >= b.len { |
| 128 | j = 0 |
| 129 | } |
| 130 | } |
| 131 | unsafe { |
| 132 | *pos = j |
| 133 | } |
| 134 | return w |
| 135 | } |
| 136 | |