blowfish.ha (7565B)
1 // SPDX-License-Identifier: MIT 2 // (c) Hare authors <https://harelang.org> 3 // (c) 2010 The Go Authors. All rights reserved. 4 5 use bytes; 6 use crypto::cipher; 7 use endian; 8 9 // The block size of the Blowfish cipher in bytes. 10 export def BLOCKSZ: size = 8; 11 12 export type state = struct { 13 block: cipher::block, 14 p: [18]u32, 15 s0: [256]u32, 16 s1: [256]u32, 17 s2: [256]u32, 18 s3: [256]u32, 19 }; 20 21 const vtable: cipher::blockvtable = cipher::blockvtable { 22 blocksz = BLOCKSZ, 23 nparallel = 1, 24 encrypt = &block_encrypt, 25 decrypt = &block_decrypt, 26 finish = &block_finish, 27 }; 28 29 // Initializes a new Blowfish cipher. The user should must call [[init]] or 30 // [[init_salt]] prior to use, then may use [[crypto::cipher::encrypt]] et al. 31 // The user must call [[finish]] when they are done using the stream to securely 32 // erase secret information stored in the stream state. 33 export fn new() state = { 34 return state { 35 block = &vtable, 36 p = p, 37 s0 = s0, 38 s1 = s1, 39 s2 = s2, 40 s3 = s3, 41 }; 42 }; 43 44 // Performs key expansion for a Blowfish cipher. 45 export fn init(c: *state, key: []u8) void = { 46 let j = 0z; 47 for (let i = 0z; i < len(c.p); i += 1) { 48 c.p[i] ^= getword(key, &j); 49 }; 50 51 let l = 0u32, r = 0u32; 52 init_vector(c, &l, &r, c.p); 53 init_vector(c, &l, &r, c.s0); 54 init_vector(c, &l, &r, c.s1); 55 init_vector(c, &l, &r, c.s2); 56 init_vector(c, &l, &r, c.s3); 57 }; 58 59 fn init_vector(c: *state, l: *u32, r: *u32, vec: []u32) void = { 60 for (let i = 0z; i < len(vec); i += 2) { 61 const (v0, v1) = encrypt(c, *l, *r); 62 *l = v0; 63 *r = v1; 64 vec[i] = *l; 65 vec[i+1] = *r; 66 }; 67 }; 68 69 // Performs salted key expansion for a Blowfish cipher. 70 export fn init_salt(c: *state, key: []u8, salt: []u8) void = { 71 if (len(salt) == 0) { 72 init(c, key); 73 return; 74 }; 75 76 assert(len(key) >= 1, "Invalid blowfish key size"); 77 let j = 0z; 78 for (let i = 0z; i < 18; i += 1) { 79 c.p[i] ^= getword(key, &j); 80 }; 81 82 j = 0; 83 let l = 0u32, r = 0u32; 84 init_vector_salt(c, &l, &r, c.p, salt, &j); 85 init_vector_salt(c, &l, &r, c.s0, salt, &j); 86 init_vector_salt(c, &l, &r, c.s1, salt, &j); 87 init_vector_salt(c, &l, &r, c.s2, salt, &j); 88 init_vector_salt(c, &l, &r, c.s3, salt, &j); 89 }; 90 91 fn init_vector_salt( 92 c: *state, 93 l: *u32, 94 r: *u32, 95 vec: []u32, 96 salt: []u8, 97 j: *size, 98 ) void = { 99 for (let i = 0z; i < len(vec); i += 2) { 100 *l ^= getword(salt, j); 101 *r ^= getword(salt, j); 102 const (v0, v1) = encrypt(c, *l, *r); 103 *l = v0; 104 *r = v1; 105 vec[i] = *l; 106 vec[i+1] = *r; 107 }; 108 }; 109 110 fn block_encrypt(c: *cipher::block, dest: []u8, src: []u8) void = { 111 const c = c: *state; 112 assert(c.block.encrypt == &block_encrypt); 113 114 let l = src[0]<<24u32 | src[1]<<16u32 | src[2]<<8u32 | src[3]: u32; 115 let r = src[4]<<24u32 | src[5]<<16u32 | src[6]<<8u32 | src[7]: u32; 116 const (l, r) = encrypt(c, l, r); 117 dest[0] = (l>>24): u8; 118 dest[1] = (l>>16): u8; 119 dest[2] = (l>>8): u8; 120 dest[3] = l: u8; 121 dest[4] = (r>>24): u8; 122 dest[5] = (r>>16): u8; 123 dest[6] = (r>>8): u8; 124 dest[7] = r: u8; 125 }; 126 127 fn block_decrypt(c: *cipher::block, dest: []u8, src: []u8) void = { 128 const c = c: *state; 129 assert(c.block.decrypt == &block_decrypt); 130 131 let l = src[0]<<24u32 | src[1]<<16u32 | src[2]<<8u32 | src[3]: u32; 132 let r = src[4]<<24u32 | src[5]<<16u32 | src[6]<<8u32 | src[7]: u32; 133 const v = decrypt(c, l, r); 134 l = v.0; 135 r = v.1; 136 dest[0] = (l>>24): u8; 137 dest[1] = (l>>16): u8; 138 dest[2] = (l>>8): u8; 139 dest[3] = l: u8; 140 dest[4] = (r>>24): u8; 141 dest[5] = (r>>16): u8; 142 dest[6] = (r>>8): u8; 143 dest[7] = r: u8; 144 }; 145 146 fn block_finish(cipher: *cipher::block) void = { 147 const cipher = cipher: *state; 148 assert(cipher.block.finish == &block_finish); 149 bytes::zero((&cipher.p: *[*]u8)[..len(cipher.p) * size(u32)]); 150 bytes::zero((&cipher.s0: *[*]u8)[..len(cipher.s0) * size(u32)]); 151 bytes::zero((&cipher.s1: *[*]u8)[..len(cipher.s1) * size(u32)]); 152 bytes::zero((&cipher.s2: *[*]u8)[..len(cipher.s2) * size(u32)]); 153 bytes::zero((&cipher.s3: *[*]u8)[..len(cipher.s3) * size(u32)]); 154 }; 155 156 fn encrypt(c: *state, l: u32, r: u32) (u32, u32) = { 157 let xl = l, xr = r; 158 xl ^= c.p[0]; 159 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[1]; 160 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[2]; 161 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[3]; 162 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[4]; 163 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[5]; 164 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[6]; 165 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[7]; 166 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[8]; 167 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[9]; 168 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[10]; 169 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[11]; 170 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[12]; 171 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[13]; 172 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[14]; 173 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[15]; 174 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[16]; 175 xr ^= c.p[17]; 176 return (xr, xl); 177 }; 178 179 fn decrypt(c: *state, l: u32, r: u32) (u32, u32) = { 180 let xl = l, xr = r; 181 xl ^= c.p[17]; 182 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[16]; 183 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[15]; 184 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[14]; 185 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[13]; 186 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[12]; 187 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[11]; 188 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[10]; 189 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[9]; 190 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[8]; 191 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[7]; 192 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[6]; 193 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[5]; 194 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[4]; 195 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[3]; 196 xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[2]; 197 xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[1]; 198 xr ^= c.p[0]; 199 return (xr, xl); 200 }; 201 202 // Gets the next word from b and updates the index, looping around in a circular 203 // buffer. 204 fn getword(b: []u8, i: *size) u32 = { 205 let j = *i; 206 let w = 0u32; 207 for (let i = 0; i < 4; i += 1) { 208 w = w<<8 | b[j]: u32; 209 j += 1; 210 if (j >= len(b)) { 211 j = 0; 212 }; 213 }; 214 *i = j; 215 return w; 216 };