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