authenc.ha (13514B)
1 // License: MPL-2.0 2 // (c) 2022 Armin Preiml <apreiml@strohwolke.at> 3 use bytes; 4 use errors; 5 6 type sample = struct { 7 msg: []u8, 8 cipher: []u8, 9 additional: []u8, 10 key: sessionkey, 11 nonce: nonce, 12 mac: mac, 13 }; 14 15 // test vector taken from the XChacha20-Poly1305-AEAD draft rfc 16 const rfcsample: sample = sample { 17 msg = [ 18 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 19 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 20 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 21 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 22 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, 0x6f, 0x75, 23 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 24 0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 25 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 26 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 27 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, 0x63, 0x72, 0x65, 0x65, 28 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 29 0x20, 0x69, 0x74, 0x2e, 30 ], 31 additional = [ 32 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 33 0xc6, 0xc7, 34 ], 35 key = [ 36 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 37 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 38 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 39 0x9e, 0x9f, 40 ], 41 nonce = [ 42 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 43 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 44 0x54, 0x55, 0x56, 0x57, 45 ], 46 cipher = [ 47 0xbd, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b, 0x95, 0x76, 48 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39, 0x57, 0x2a, 0x17, 0x00, 49 0x25, 0x2b, 0xfa, 0xcc, 0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 50 0x6c, 0xbb, 0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44, 51 0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39, 0xae, 0x64, 52 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16, 0xcb, 0x96, 0xb7, 0x2e, 53 0x12, 0x13, 0xb4, 0x52, 0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 54 0xd9, 0x45, 0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e, 55 0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f, 0x76, 0xb2, 56 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9, 0x21, 0xf9, 0x66, 0x4c, 57 0x97, 0x63, 0x7d, 0xa9, 0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 58 0x8b, 0x13, 0xb5, 0x2e, 59 ], 60 mac = [ 61 0xc0, 0x87, 0x59, 0x24, 0xc1, 0xc7, 0x98, 0x79, 0x47, 0xde, 62 0xaf, 0xd8, 0x78, 0x0a, 0xcf, 0x49, 63 ], 64 }; 65 66 67 const noadsample: sample = sample { 68 key = [ 69 0xdf, 0x23, 0xf4, 0xad, 0xe4, 0x6f, 0xc1, 0x41, 0x36, 0xe6, 70 0x63, 0x48, 0x3c, 0xcd, 0x74, 0x56, 0x44, 0x6a, 0x56, 0x56, 71 0xd8, 0xb4, 0x34, 0x30, 0xd4, 0xfd, 0x7b, 0xa8, 0x2c, 0x60, 72 0xf7, 0x62, 73 ], 74 msg = [ 75 0x9b, 0x0e, 0x38, 0x4b, 0x29, 0x09, 0x8e, 0xa3, 0xb4, 0x37, 76 0x7c, 0x81, 0xba, 0xc0, 0xbf, 0x7e, 0x59, 0xc2, 0xdc, 0x0f, 77 0x43, 0x03, 0x40, 0x1f, 0xd4, 0x1b, 0xae, 0x69, 0xfd, 0x0f, 78 0x0f, 0x49, 0xc8, 0xef, 0xa2, 0x30, 0x21, 0x53, 0x4a, 0xfc, 79 0x0c, 0xa6, 0xef, 0x3c, 0x34, 0xe9, 0x9c, 0xc7, 0x8b, 0xd7, 80 0xe6, 0x02, 0xcd, 0xc5, 0x28, 0x43, 0x42, 0xe3, 0xdf, 0x32, 81 0xf2, 0x28, 0xd9, 0x09, 0xca, 0xa4, 0x45, 0x19, 0x2a, 0x9e, 82 0x2d, 0x99, 0xf1, 0x40, 0x55, 0x2f, 0xb4, 0xe0, 0x04, 0xd8, 83 0x3b, 0x2e, 0x1e, 0xed, 0xff, 0xa6, 0x51, 0xd2, 0xe1, 0x22, 84 ], 85 nonce = [ 86 0xe2, 0x5b, 0x34, 0x1f, 0xc2, 0x8b, 0x6e, 0xc3, 0x37, 0xa0, 87 0x92, 0x45, 0xa8, 0xcb, 0x4b, 0x40, 0x3f, 0x24, 0x1c, 0x95, 88 0xff, 0x72, 0xea, 0x1d, 89 ], 90 cipher = [ 91 0x0b, 0xec, 0x57, 0xc8, 0x58, 0xf0, 0xc6, 0xb3, 0x42, 0x94, 92 0x86, 0xce, 0xf3, 0x3f, 0x04, 0x19, 0x41, 0xc2, 0xf7, 0xc9, 93 0x1f, 0x12, 0x9c, 0xbd, 0x68, 0xa8, 0xf2, 0xbe, 0xd3, 0xf3, 94 0x11, 0xea, 0x6e, 0xae, 0x39, 0xca, 0x93, 0x06, 0x99, 0x70, 95 0x67, 0xd6, 0xfa, 0xd8, 0x16, 0x4b, 0x2d, 0xf3, 0xb4, 0x73, 96 0x22, 0x36, 0x4b, 0x2d, 0xac, 0xd2, 0xaa, 0xab, 0x13, 0x2a, 97 0xd7, 0x05, 0x15, 0xbf, 0x18, 0x56, 0x20, 0xdb, 0xa4, 0xbb, 98 0x38, 0xa8, 0x8b, 0x0d, 0x12, 0xcc, 0x3b, 0x47, 0x4c, 0xba, 99 0x5f, 0x11, 0x75, 0x4e, 0x34, 0x87, 0x14, 0xe9, 0xb1, 0x23, 100 ], 101 mac = [ 102 0x07, 0x92, 0x76, 0xd8, 0x7c, 0x77, 0x71, 0x4b, 0xa4, 0xf2, 103 0x27, 0x66, 0x79, 0xeb, 0x38, 0xc1, 104 ], 105 ... 106 }; 107 108 const nomsg: sample = sample { 109 key = [ 110 0x10, 0x28, 0xbe, 0x0e, 0x0e, 0x46, 0x38, 0x0f, 0x12, 0x9f, 111 0x56, 0x17, 0x21, 0xb8, 0x65, 0x44, 0x49, 0x0d, 0x48, 0x7a, 112 0x46, 0x79, 0x5b, 0x9c, 0x54, 0xfd, 0x42, 0xc4, 0x53, 0x82, 113 0x51, 0x14, 114 ], 115 nonce = [ 116 0x35, 0x54, 0xec, 0x93, 0x4d, 0xd5, 0xdc, 0x90, 0xa2, 0xd3, 117 0x72, 0xdc, 0xff, 0x0a, 0x73, 0x32, 0x5f, 0xbd, 0xcc, 0x36, 118 0xab, 0x3f, 0x47, 0x1c, 119 ], 120 additional = [ 121 0xbe, 0x71, 0xf2, 0x86, 0x5a, 0xb9, 0x1b, 0x3c, 0x07, 0x9b, 122 0xa3, 0x3a, 0x34, 0xa3, 0x5e, 0x4a, 0x51, 0x34, 0xf5, 0x02, 123 0x55, 0xb1, 0x97, 0x1d, 0xd8, 0xb8, 0xb0, 0x63, 0x07, 0x98, 124 0x11, 0x7c, 0x4e, 0x40, 0xd1, 0xfe, 0xf7, 0x8d, 0xc8, 0xbc, 125 0x45, 0x3c, 0x1f, 0x81, 0x2d, 0xf2, 0x98, 0x88, 0x36, 0x9d, 126 0x0d, 0x2f, 0x71, 0xf5, 0xdb, 0x9d, 0x05, 0x5e, 0xc5, 0x4d, 127 0x6d, 0xe3, 0xca, 0xbb, 0x46, 0xda, 0x99, 0x41, 0xb1, 0xcd, 128 0x4e, 0xdc, 0xa3, 0x82, 0xc1, 0xb7, 0xd3, 0x5b, 0xae, 0x41, 129 0x60, 0x6a, 0x59, 0x2e, 0xf9, 0xd3, 0xbf, 0x44, 0x95, 0xbd, 130 ], 131 mac = [ 132 0xe9, 0x50, 0xd4, 0x3f, 0x0a, 0x84, 0x69, 0x24, 0xa3, 0x9a, 133 0xe6, 0x06, 0x29, 0xf8, 0x16, 0xcf, 134 ], 135 ... 136 }; 137 138 const nothing: sample = sample { 139 key = [ 140 0xbb, 0xf5, 0xf5, 0x40, 0xd7, 0x21, 0x38, 0x22, 0xe2, 0x82, 141 0x34, 0x0e, 0x26, 0xaa, 0x0a, 0xce, 0x94, 0x76, 0xb1, 0xac, 142 0x62, 0x50, 0x3f, 0x1a, 0x7c, 0x66, 0x78, 0xb3, 0x86, 0x3e, 143 0x4d, 0x4f, 144 ], 145 nonce = [ 146 0x54, 0xe3, 0xf0, 0xa8, 0x06, 0x86, 0x26, 0xd8, 0xd7, 0x7e, 147 0x26, 0x23, 0x3b, 0x95, 0xbf, 0x44, 0x30, 0x9e, 0xf6, 0xe4, 148 0x00, 0x65, 0xff, 0x1a, 149 ], 150 mac = [ 151 0x14, 0x23, 0x9b, 0xb3, 0xa3, 0x35, 0x9a, 0x11, 0x9c, 0x1d, 152 0x79, 0x65, 0x4b, 0xe2, 0x2f, 0xaf, 153 ], 154 ... 155 }; 156 157 const polyaligned: sample = sample { 158 key = [ 159 0x8a, 0x67, 0xe3, 0x6c, 0x24, 0xbd, 0x05, 0x7f, 0x53, 0x7d, 160 0x3b, 0x2d, 0x25, 0x98, 0x7c, 0x21, 0xb1, 0x51, 0x90, 0xdd, 161 0x7a, 0x4a, 0x52, 0x49, 0x12, 0x22, 0x3e, 0x7e, 0x2e, 0x0d, 162 0x8a, 0x15, 163 ], 164 msg = [ 165 0xa1, 0x9c, 0x40, 0xbe, 0x6e, 0xf7, 0x43, 0x66, 0xcf, 0xe1, 166 0x15, 0xce, 0x0c, 0x90, 0x7c, 0x1f, 0x35, 0xfb, 0x03, 0x7f, 167 0x96, 0x62, 0x53, 0xa6, 0xfa, 0xf1, 0x31, 0x39, 0xae, 0x69, 168 0x0e, 0xf7, 169 ], 170 nonce = [ 171 0xc2, 0x16, 0x80, 0x49, 0xd1, 0x82, 0x04, 0xc5, 0x89, 0xee, 172 0xbc, 0x24, 0xa0, 0x37, 0x6f, 0xbb, 0x44, 0x09, 0x49, 0x8e, 173 0xe2, 0x73, 0x33, 0x4d, 174 ], 175 additional = [ 176 0xc1, 0xf7, 0xa5, 0xcf, 0x2f, 0xc0, 0x21, 0x55, 0x74, 0xfb, 177 0x75, 0xcd, 0x8b, 0x9e, 0xe2, 0x2a, 178 ], 179 cipher = [ 180 0xfe, 0xe1, 0xb9, 0xff, 0xc5, 0x03, 0x38, 0x73, 0xbb, 0x1c, 181 0x90, 0x7b, 0x53, 0x39, 0x65, 0xd7, 0x64, 0x12, 0xe4, 0x88, 182 0xa0, 0xaa, 0x8e, 0x11, 0x23, 0xd0, 0x20, 0x8a, 0x54, 0x76, 183 0x12, 0x75, 184 ], 185 mac = [ 186 0x7e, 0x80, 0x2c, 0x34, 0x45, 0x04, 0x5b, 0xff, 0x04, 0x58, 187 0x36, 0xef, 0xe2, 0x55, 0xc8, 0x45, 188 ], 189 }; 190 191 @test fn rfc() void = { 192 let result: []u8 = alloc(rfcsample.msg...); 193 defer free(result); 194 195 let b = encrypt(&rfcsample.key, &rfcsample.nonce, result[..], 196 rfcsample.additional[..]); 197 198 assert(bytes::equal(rfcsample.cipher, b.2)); 199 assert(bytes::equal(rfcsample.nonce, b.1)); 200 assert(bytes::equal(rfcsample.mac, b.0)); 201 202 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); 203 204 assert(plain is []u8); 205 assert(bytes::equal(rfcsample.msg, plain as []u8)); 206 }; 207 208 @test fn rfcmultiadditonals() void = { 209 let result: []u8 = alloc(rfcsample.msg...); 210 defer free(result); 211 212 let b = encrypt(&rfcsample.key, &rfcsample.nonce, result[..], 213 rfcsample.additional[..4], rfcsample.additional[4..]); 214 215 assert(bytes::equal(rfcsample.cipher, b.2)); 216 assert(bytes::equal(rfcsample.nonce, b.1)); 217 assert(bytes::equal(rfcsample.mac, b.0)); 218 219 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); 220 221 assert(plain is []u8); 222 assert(bytes::equal(rfcsample.msg, plain as []u8)); 223 }; 224 225 @test fn noadditional() void = { 226 let result: []u8 = alloc(noadsample.msg...); 227 defer free(result); 228 229 let b = encrypt(&noadsample.key, &noadsample.nonce, result[..]); 230 231 assert(bytes::equal(noadsample.cipher, b.2)); 232 assert(bytes::equal(noadsample.nonce, b.1)); 233 assert(bytes::equal(noadsample.mac, b.0)); 234 235 const plain = decrypt(&noadsample.key, &b); 236 237 assert(plain is []u8); 238 assert(bytes::equal(noadsample.msg, plain as []u8)); 239 }; 240 241 @test fn nomsg() void = { 242 let result: []u8 = []; 243 defer free(result); 244 245 let b = encrypt(&nomsg.key, &nomsg.nonce, result[..], nomsg.additional); 246 247 assert(bytes::equal([], b.2)); 248 assert(bytes::equal(nomsg.nonce, b.1)); 249 assert(bytes::equal(nomsg.mac, b.0)); 250 251 const plain = decrypt(&nomsg.key, &b, nomsg.additional); 252 253 assert(plain is []u8); 254 assert(bytes::equal([], plain as []u8)); 255 }; 256 257 @test fn nothing() void = { 258 let result: []u8 = []; 259 defer free(result); 260 261 let b = encrypt(¬hing.key, ¬hing.nonce, result[..]); 262 263 assert(bytes::equal([], b.2)); 264 assert(bytes::equal(nothing.nonce, b.1)); 265 assert(bytes::equal(nothing.mac, b.0)); 266 267 const plain = decrypt(¬hing.key, &b); 268 269 assert(plain is []u8); 270 assert(bytes::equal([], plain as []u8)); 271 }; 272 273 @test fn polyaligned() void = { 274 let result: []u8 = alloc(polyaligned.msg...); 275 defer free(result); 276 277 let b = encrypt(&polyaligned.key, &polyaligned.nonce, result[..], 278 polyaligned.additional[..]); 279 280 assert(bytes::equal(polyaligned.cipher, b.2)); 281 assert(bytes::equal(polyaligned.nonce, b.1)); 282 assert(bytes::equal(polyaligned.mac, b.0)); 283 284 const plain = decrypt(&polyaligned.key, &b, polyaligned.additional); 285 286 assert(plain is []u8); 287 assert(bytes::equal(polyaligned.msg, plain as []u8)); 288 }; 289 290 291 @test fn invalidkey() void = { 292 const zero: [114]u8 = [0...]; 293 294 let key = rfcsample.key; 295 key[0] = 0x00; 296 297 let cipher: []u8 = alloc(rfcsample.cipher...); 298 defer free(cipher); 299 300 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 301 302 const plain = decrypt(&key, &b, rfcsample.additional); 303 304 assert(plain is errors::invalid); 305 assert(bytes::equal(zero, cipher)); 306 }; 307 308 @test fn invalidcipher() void = { 309 const zero: [114]u8 = [0...]; 310 311 let cipher: []u8 = alloc(rfcsample.cipher...); 312 defer free(cipher); 313 cipher[0] = 0x00; 314 315 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 316 317 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); 318 319 assert(plain is errors::invalid); 320 assert(bytes::equal(zero, cipher)); 321 }; 322 323 @test fn invalidcipher2() void = { 324 325 let cipher: []u8 = alloc(rfcsample.cipher...); 326 defer free(cipher); 327 append(cipher, 0xff); 328 329 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 330 331 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); 332 333 assert(plain is errors::invalid); 334 335 const zero: [115]u8 = [0...]; 336 assert(bytes::equal(zero, cipher)); 337 }; 338 339 @test fn invalidcipher3() void = { 340 let cipher: []u8 = alloc(rfcsample.cipher...); 341 defer free(cipher); 342 delete(cipher[len(cipher) - 1]); 343 344 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 345 346 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); 347 348 assert(plain is errors::invalid); 349 350 const zero: [113]u8 = [0...]; 351 assert(bytes::equal(zero, cipher)); 352 }; 353 354 @test fn invalidaddition() void = { 355 const zero: [114]u8 = [0...]; 356 357 let cipher: []u8 = alloc(rfcsample.cipher...); 358 defer free(cipher); 359 360 let ad: []u8 = alloc(rfcsample.additional...); 361 defer free(ad); 362 ad[0] = 0x00; 363 364 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 365 366 const plain = decrypt(&rfcsample.key, &b, ad); 367 368 assert(plain is errors::invalid); 369 assert(bytes::equal(zero, cipher)); 370 }; 371 372 @test fn invalidaddition2() void = { 373 const zero: [114]u8 = [0...]; 374 375 let cipher: []u8 = alloc(rfcsample.cipher...); 376 defer free(cipher); 377 378 let ad: []u8 = alloc(rfcsample.additional...); 379 defer free(ad); 380 append(ad, 0xff); 381 382 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 383 384 const plain = decrypt(&rfcsample.key, &b, ad); 385 386 assert(plain is errors::invalid); 387 assert(bytes::equal(zero, cipher)); 388 }; 389 390 @test fn invalidaddition3() void = { 391 const zero: [114]u8 = [0...]; 392 393 let cipher: []u8 = alloc(rfcsample.cipher...); 394 defer free(cipher); 395 396 let ad: []u8 = alloc(rfcsample.additional...); 397 defer free(ad); 398 delete(ad[len(ad) - 1]); 399 400 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 401 402 const plain = decrypt(&rfcsample.key, &b, ad); 403 404 assert(plain is errors::invalid); 405 assert(bytes::equal(zero, cipher)); 406 }; 407 408 @test fn invalidaddition4() void = { 409 const zero: [114]u8 = [0...]; 410 411 let cipher: []u8 = alloc(rfcsample.cipher...); 412 defer free(cipher); 413 414 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 415 416 const plain = decrypt(&rfcsample.key, &b); 417 418 assert(plain is errors::invalid); 419 assert(bytes::equal(zero, cipher)); 420 }; 421 422 @test fn invalidaddition5() void = { 423 const zero: [114]u8 = [0...]; 424 425 let cipher: []u8 = alloc(rfcsample.cipher...); 426 defer free(cipher); 427 428 let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); 429 430 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional, [0xff]); 431 432 assert(plain is errors::invalid); 433 assert(bytes::equal(zero, cipher)); 434 }; 435 436 @test fn cipheradditionswap() void = { 437 let additional: []u8 = alloc(rfcsample.additional...); 438 defer free(additional); 439 440 let b: box = (rfcsample.mac, rfcsample.nonce, additional); 441 442 const plain = decrypt(&rfcsample.key, &b, rfcsample.cipher); 443 444 assert(plain is errors::invalid); 445 446 const zero: [12]u8 = [0...]; 447 assert(bytes::equal(zero, additional)); 448 }; 449 450 @test fn invalidmac() void = { 451 const zero: [114]u8 = [0...]; 452 453 let cipher: []u8 = alloc(rfcsample.cipher...); 454 defer free(cipher); 455 456 let mac: mac = rfcsample.mac; 457 mac[0] = 0xff; 458 459 let b: box = (mac, rfcsample.nonce, cipher[..]); 460 461 const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); 462 463 assert(plain is errors::invalid); 464 assert(bytes::equal(zero, cipher)); 465 };