aez.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. // aez.go - An AEZ implementation.
  2. //
  3. // To the extent possible under law, Yawning Angel has waived all copyright
  4. // and related or neighboring rights to aez, using the Creative
  5. // Commons "CC0" public domain dedication. See LICENSE or
  6. // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
  7. //
  8. // This implementation is primarily derived from the AEZ v5 reference code
  9. // available at: http://www.cs.ucdavis.edu/~rogaway/aez
  10. //
  11. // It started off as a straight forward port of the `ref` variant, but has
  12. // pulled in ideas from `aesni`.
  13. // Package aez implements the AEZ AEAD primitive.
  14. //
  15. // See: http://web.cs.ucdavis.edu/~rogaway/aez/
  16. package aez
  17. import (
  18. "crypto/subtle"
  19. "encoding/binary"
  20. "math"
  21. "golang.org/x/crypto/blake2b"
  22. )
  23. const (
  24. // Version is the version of the AEZ specification implemented.
  25. Version = "v5"
  26. extractedKeySize = 3 * 16
  27. blockSize = 16
  28. )
  29. var (
  30. newAes aesImplCtor = nil
  31. zero = [blockSize]byte{}
  32. isHardwareAccelerated = false
  33. )
  34. func extract(k []byte, extractedKey *[extractedKeySize]byte) {
  35. if len(k) == extractedKeySize {
  36. copy(extractedKey[:], k)
  37. } else {
  38. h, err := blake2b.New(extractedKeySize, nil)
  39. if err != nil {
  40. panic("aez: Extract: " + err.Error())
  41. }
  42. defer h.Reset()
  43. h.Write(k)
  44. tmp := h.Sum(nil)
  45. copy(extractedKey[:], tmp)
  46. memwipe(tmp)
  47. }
  48. }
  49. type aesImpl interface {
  50. Reset()
  51. AES4(j, i, l *[blockSize]byte, src []byte, dst *[blockSize]byte)
  52. AES10(l *[blockSize]byte, src []byte, dst *[blockSize]byte)
  53. }
  54. type aesImplCtor func(*[extractedKeySize]byte) aesImpl
  55. type eState struct {
  56. I [2][16]byte // 1I, 2I
  57. J [3][16]byte // 1J, 2J, 4J
  58. L [8][16]byte // 0L, 1L ... 7L
  59. aes aesImpl
  60. }
  61. func (e *eState) init(k []byte) {
  62. var extractedKey [extractedKeySize]byte
  63. defer memwipe(extractedKey[:])
  64. extract(k, &extractedKey)
  65. copy(e.I[0][:], extractedKey[0:16]) // 1I
  66. multBlock(2, &e.I[0], &e.I[1]) // 2I
  67. copy(e.J[0][:], extractedKey[16:32]) // 1J
  68. multBlock(2, &e.J[0], &e.J[1]) // 2J
  69. multBlock(2, &e.J[1], &e.J[2]) // 4J
  70. // The upstream `aesni` code only stores L1, L2, and L4, but it has
  71. // the benefit of being written in a real language that has vector
  72. // intrinsics.
  73. // multBlock(0, &e.L, &e.L[0]) // L0 (all `0x00`s)
  74. copy(e.L[1][:], extractedKey[32:48]) // L1
  75. multBlock(2, &e.L[1], &e.L[2]) // L2 = L1*2
  76. xorBytes1x16(e.L[2][:], e.L[1][:], e.L[3][:]) // L3 = L2+L1
  77. multBlock(2, &e.L[2], &e.L[4]) // L4 = L2*2
  78. xorBytes1x16(e.L[4][:], e.L[1][:], e.L[5][:]) // L5 = L4+L1
  79. multBlock(2, &e.L[3], &e.L[6]) // L6 = L3*2
  80. xorBytes1x16(e.L[6][:], e.L[1][:], e.L[7][:]) // L7 = L6+L1
  81. e.aes = newAes(&extractedKey)
  82. }
  83. func (e *eState) reset() {
  84. for i := range e.I {
  85. memwipe(e.I[i][:])
  86. }
  87. for i := range e.J {
  88. memwipe(e.J[i][:])
  89. }
  90. for i := range e.L {
  91. memwipe(e.L[i][:])
  92. }
  93. e.aes.Reset()
  94. }
  95. func multBlock(x uint, src, dst *[blockSize]byte) {
  96. var t, r [blockSize]byte
  97. copy(t[:], src[:])
  98. for x != 0 {
  99. if x&1 != 0 { // This is fine, x isn't data/secret dependent.
  100. xorBytes1x16(r[:], t[:], r[:])
  101. }
  102. doubleBlock(&t)
  103. x >>= 1
  104. }
  105. copy(dst[:], r[:])
  106. memwipe(t[:])
  107. memwipe(r[:])
  108. }
  109. func doubleBlock(p *[blockSize]byte) {
  110. tmp := p[0]
  111. for i := 0; i < 15; i++ {
  112. p[i] = (p[i] << 1) | (p[i+1] >> 7)
  113. }
  114. // p[15] = (p[15] << 1) ^ ((tmp >> 7)?135:0);
  115. s := subtle.ConstantTimeByteEq(tmp>>7, 1)
  116. p[15] = (p[15] << 1) ^ byte(subtle.ConstantTimeSelect(s, 135, 0))
  117. }
  118. func (e *eState) aezHash(nonce []byte, ad [][]byte, tau int, result []byte) {
  119. var buf, sum, I, J [blockSize]byte
  120. if len(result) != blockSize {
  121. panic("aez: Hash: len(result)")
  122. }
  123. // Initialize sum with hash of tau
  124. binary.BigEndian.PutUint32(buf[12:], uint32(tau))
  125. xorBytes1x16(e.J[0][:], e.J[1][:], J[:]) // J ^ J2
  126. e.aes.AES4(&J, &e.I[1], &e.L[1], buf[:], &sum) // E(3,1)
  127. // Hash nonce, accumulate into sum
  128. empty := len(nonce) == 0
  129. n := nonce
  130. nBytes := uint(len(nonce))
  131. copy(I[:], e.I[1][:])
  132. for i := uint(1); nBytes >= blockSize; i, nBytes = i+1, nBytes-blockSize {
  133. e.aes.AES4(&e.J[2], &I, &e.L[i%8], n[:blockSize], &buf) // E(4,i)
  134. xorBytes1x16(sum[:], buf[:], sum[:])
  135. n = n[blockSize:]
  136. if i%8 == 0 {
  137. doubleBlock(&I)
  138. }
  139. }
  140. if nBytes > 0 || empty {
  141. memwipe(buf[:])
  142. copy(buf[:], n)
  143. buf[nBytes] = 0x80
  144. e.aes.AES4(&e.J[2], &e.I[0], &e.L[0], buf[:], &buf) // E(4,0)
  145. xorBytes1x16(sum[:], buf[:], sum[:])
  146. }
  147. // Hash each vector element, accumulate into sum
  148. for k, p := range ad {
  149. empty = len(p) == 0
  150. bytes := uint(len(p))
  151. copy(I[:], e.I[1][:])
  152. multBlock(uint(5+k), &e.J[0], &J) // XXX/performance.
  153. for i := uint(1); bytes >= blockSize; i, bytes = i+1, bytes-blockSize {
  154. e.aes.AES4(&J, &I, &e.L[i%8], p[:blockSize], &buf) // E(5+k,i)
  155. xorBytes1x16(sum[:], buf[:], sum[:])
  156. p = p[blockSize:]
  157. if i%8 == 0 {
  158. doubleBlock(&I)
  159. }
  160. }
  161. if bytes > 0 || empty {
  162. memwipe(buf[:])
  163. copy(buf[:], p)
  164. buf[bytes] = 0x80
  165. e.aes.AES4(&J, &e.I[0], &e.L[0], buf[:], &buf) // E(5+k,0)
  166. xorBytes1x16(sum[:], buf[:], sum[:])
  167. }
  168. }
  169. memwipe(I[:])
  170. memwipe(J[:])
  171. copy(result, sum[:])
  172. }
  173. func (e *eState) aezPRF(delta *[blockSize]byte, tau int, result []byte) {
  174. var buf, ctr [blockSize]byte
  175. off := 0
  176. for tau >= blockSize {
  177. xorBytes1x16(delta[:], ctr[:], buf[:])
  178. e.aes.AES10(&e.L[3], buf[:], &buf) // E(-1,3)
  179. copy(result[off:], buf[:])
  180. i := 15
  181. for { // ctr += 1
  182. ctr[i]++
  183. i--
  184. if ctr[i+1] != 0 {
  185. break
  186. }
  187. }
  188. tau -= blockSize
  189. off += blockSize
  190. }
  191. if tau > 0 {
  192. xorBytes1x16(delta[:], ctr[:], buf[:])
  193. e.aes.AES10(&e.L[3], buf[:], &buf) // E(-1,3)
  194. copy(result[off:], buf[:])
  195. }
  196. memwipe(buf[:])
  197. }
  198. func (e *eState) aezCorePass1Slow(in, out []byte, X *[blockSize]byte, sz int) {
  199. // NB: The hardware accelerated case is handled prior to this function.
  200. // Use one of the portable bitsliced options if possible.
  201. switch a := e.aes.(type) {
  202. case *roundB32:
  203. a.aezCorePass1(e, in, out, X, sz)
  204. case *roundB64:
  205. a.aezCorePass1(e, in, out, X, sz)
  206. default:
  207. e.aezCorePass1Ref(in, out, X)
  208. }
  209. }
  210. func (e *eState) aezCorePass2Slow(in, out []byte, Y, S *[blockSize]byte, sz int) {
  211. // NB: The hardware accelerated case is handled prior to this function.
  212. // Use one of the portable bitsliced options if possible.
  213. switch a := e.aes.(type) {
  214. case *roundB32:
  215. a.aezCorePass2(e, out, Y, S, sz)
  216. case *roundB64:
  217. a.aezCorePass2(e, out, Y, S, sz)
  218. default:
  219. e.aezCorePass2Ref(in, out, Y, S)
  220. }
  221. }
  222. func (e *eState) aezCorePass1Ref(in, out []byte, X *[blockSize]byte) {
  223. var tmp, I [blockSize]byte
  224. copy(I[:], e.I[1][:])
  225. for i, inBytes := uint(1), len(in); inBytes >= 64; i, inBytes = i+1, inBytes-32 {
  226. e.aes.AES4(&e.J[0], &I, &e.L[i%8], in[blockSize:blockSize*2], &tmp) // E(1,i)
  227. xorBytes1x16(in[:], tmp[:], out[:blockSize])
  228. e.aes.AES4(&zero, &e.I[0], &e.L[0], out[:blockSize], &tmp) // E(0,0)
  229. xorBytes1x16(in[blockSize:], tmp[:], out[blockSize:blockSize*2])
  230. xorBytes1x16(out[blockSize:], X[:], X[:])
  231. in, out = in[32:], out[32:]
  232. if i%8 == 0 {
  233. doubleBlock(&I)
  234. }
  235. }
  236. memwipe(tmp[:])
  237. memwipe(I[:])
  238. }
  239. func (e *eState) aezCorePass2Ref(in, out []byte, Y, S *[blockSize]byte) {
  240. var tmp, I [blockSize]byte
  241. copy(I[:], e.I[1][:])
  242. for i, inBytes := uint(1), len(in); inBytes >= 64; i, inBytes = i+1, inBytes-32 {
  243. e.aes.AES4(&e.J[1], &I, &e.L[i%8], S[:], &tmp) // E(2,i)
  244. xorBytes1x16(out, tmp[:], out[:blockSize])
  245. xorBytes1x16(out[blockSize:], tmp[:], out[blockSize:blockSize*2])
  246. xorBytes1x16(out, Y[:], Y[:])
  247. e.aes.AES4(&zero, &e.I[0], &e.L[0], out[blockSize:blockSize*2], &tmp) // E(0,0)
  248. xorBytes1x16(out, tmp[:], out[:blockSize])
  249. e.aes.AES4(&e.J[0], &I, &e.L[i%8], out[:blockSize], &tmp) // E(1,i)
  250. xorBytes1x16(out[blockSize:], tmp[:], out[blockSize:blockSize*2])
  251. swapBlocks(&tmp, out)
  252. in, out = in[32:], out[32:]
  253. if i%8 == 0 {
  254. doubleBlock(&I)
  255. }
  256. }
  257. memwipe(I[:])
  258. memwipe(tmp[:])
  259. }
  260. func oneZeroPad(src []byte, sz int, dst *[blockSize]byte) {
  261. memwipe(dst[:])
  262. copy(dst[:], src[:sz])
  263. dst[sz] = 0x80
  264. }
  265. func (e *eState) aezCore(delta *[blockSize]byte, in []byte, d uint, out []byte) {
  266. var tmp, X, Y, S [blockSize]byte
  267. outOrig, inOrig := out, in
  268. fragBytes := len(in) % 32
  269. initialBytes := len(in) - fragBytes - 32
  270. // Compute X and store intermediate results
  271. // Pass 1 over in[0:-32], store intermediate values in out[0:-32]
  272. if len(in) >= 64 {
  273. e.aezCorePass1(in, out, &X, initialBytes)
  274. }
  275. // Finish X calculation
  276. in = in[initialBytes:]
  277. if fragBytes >= blockSize {
  278. e.aes.AES4(&zero, &e.I[1], &e.L[4], in[:blockSize], &tmp) // E(0,4)
  279. xorBytes1x16(X[:], tmp[:], X[:])
  280. oneZeroPad(in[blockSize:], fragBytes-blockSize, &tmp)
  281. e.aes.AES4(&zero, &e.I[1], &e.L[5], tmp[:], &tmp) // E(0,5)
  282. xorBytes1x16(X[:], tmp[:], X[:])
  283. } else if fragBytes > 0 {
  284. oneZeroPad(in, fragBytes, &tmp)
  285. e.aes.AES4(&zero, &e.I[1], &e.L[4], tmp[:], &tmp) // E(0,4)
  286. xorBytes1x16(X[:], tmp[:], X[:])
  287. }
  288. // Calculate S
  289. out, in = outOrig[len(inOrig)-32:], inOrig[len(inOrig)-32:]
  290. e.aes.AES4(&zero, &e.I[1], &e.L[(1+d)%8], in[blockSize:2*blockSize], &tmp) // E(0,1+d)
  291. xorBytes4x16(X[:], in[:], delta[:], tmp[:], out[:blockSize])
  292. e.aes.AES10(&e.L[(1+d)%8], out[:blockSize], &tmp) // E(-1,1+d)
  293. xorBytes1x16(in[blockSize:], tmp[:], out[blockSize:blockSize*2])
  294. xorBytes1x16(out, out[blockSize:], S[:])
  295. // XXX/performance: Early abort if tag is corrupted.
  296. // Pass 2 over intermediate values in out[32..]. Final values written
  297. out, in = outOrig, inOrig
  298. if len(in) >= 64 {
  299. e.aezCorePass2(in, out, &Y, &S, initialBytes)
  300. }
  301. // Finish Y calculation and finish encryption of fragment bytes
  302. out, in = out[initialBytes:], in[initialBytes:]
  303. if fragBytes >= blockSize {
  304. e.aes.AES10(&e.L[4], S[:], &tmp) // E(-1,4)
  305. xorBytes1x16(in, tmp[:], out[:blockSize])
  306. e.aes.AES4(&zero, &e.I[1], &e.L[4], out[:blockSize], &tmp) // E(0,4)
  307. xorBytes1x16(Y[:], tmp[:], Y[:])
  308. out, in = out[blockSize:], in[blockSize:]
  309. fragBytes -= blockSize
  310. e.aes.AES10(&e.L[5], S[:], &tmp) // E(-1,5)
  311. xorBytes(in, tmp[:], tmp[:fragBytes]) // non-16 byte xorBytes()
  312. copy(out, tmp[:fragBytes])
  313. memwipe(tmp[fragBytes:])
  314. tmp[fragBytes] = 0x80
  315. e.aes.AES4(&zero, &e.I[1], &e.L[5], tmp[:], &tmp) // E(0,5)
  316. xorBytes1x16(Y[:], tmp[:], Y[:])
  317. } else if fragBytes > 0 {
  318. e.aes.AES10(&e.L[4], S[:], &tmp) // E(-1,4)
  319. xorBytes(in, tmp[:], tmp[:fragBytes]) // non-16 byte xorBytes()
  320. copy(out, tmp[:fragBytes])
  321. memwipe(tmp[fragBytes:])
  322. tmp[fragBytes] = 0x80
  323. e.aes.AES4(&zero, &e.I[1], &e.L[4], tmp[:], &tmp) // E(0,4)
  324. xorBytes1x16(Y[:], tmp[:], Y[:])
  325. }
  326. // Finish encryption of last two blocks
  327. out = outOrig[len(inOrig)-32:]
  328. e.aes.AES10(&e.L[(2-d)%8], out[blockSize:], &tmp) // E(-1,2-d)
  329. xorBytes1x16(out, tmp[:], out[:blockSize])
  330. e.aes.AES4(&zero, &e.I[1], &e.L[(2-d)%8], out[:blockSize], &tmp) // E(0,2-d)
  331. xorBytes4x16(tmp[:], out[blockSize:], delta[:], Y[:], out[blockSize:])
  332. copy(tmp[:], out[:blockSize])
  333. copy(out[:blockSize], out[blockSize:])
  334. copy(out[blockSize:], tmp[:])
  335. memwipe(X[:])
  336. memwipe(Y[:])
  337. memwipe(S[:])
  338. }
  339. func (e *eState) aezTiny(delta *[blockSize]byte, in []byte, d uint, out []byte) {
  340. var rounds, i, j uint
  341. var buf [2 * blockSize]byte
  342. var L, R [blockSize]byte
  343. var step int
  344. mask, pad := byte(0x00), byte(0x80)
  345. defer memwipe(L[:])
  346. defer memwipe(R[:])
  347. var tmp [16]byte
  348. i = 7
  349. inBytes := len(in)
  350. if inBytes == 1 {
  351. rounds = 24
  352. } else if inBytes == 2 {
  353. rounds = 16
  354. } else if inBytes < 16 {
  355. rounds = 10
  356. } else {
  357. i, rounds = 6, 8
  358. }
  359. // Split (inbytes*8)/2 bits into L and R. Beware: May end in nibble.
  360. copy(L[:], in[:(inBytes+1)/2])
  361. copy(R[:], in[inBytes/2:inBytes/2+(inBytes+1)/2])
  362. if inBytes&1 != 0 { // Must shift R left by half a byte
  363. for k := uint(0); k < uint(inBytes/2); k++ {
  364. R[k] = (R[k] << 4) | (R[k+1] >> 4)
  365. }
  366. R[inBytes/2] = R[inBytes/2] << 4
  367. pad = 0x08
  368. mask = 0xf0
  369. }
  370. if d != 0 {
  371. if inBytes < 16 {
  372. memwipe(buf[:blockSize])
  373. copy(buf[:], in)
  374. buf[0] |= 0x80
  375. xorBytes1x16(delta[:], buf[:], buf[:blockSize])
  376. e.aes.AES4(&zero, &e.I[1], &e.L[3], buf[:blockSize], &tmp) // E(0,3)
  377. L[0] ^= (tmp[0] & 0x80)
  378. }
  379. j, step = rounds-1, -1
  380. } else {
  381. step = 1
  382. }
  383. for k := uint(0); k < rounds/2; k, j = k+1, uint(int(j)+2*step) {
  384. memwipe(buf[:blockSize])
  385. copy(buf[:], R[:(inBytes+1)/2])
  386. buf[inBytes/2] = (buf[inBytes/2] & mask) | pad
  387. xorBytes1x16(buf[:], delta[:], buf[:blockSize])
  388. buf[15] ^= byte(j)
  389. e.aes.AES4(&zero, &e.I[1], &e.L[i], buf[:blockSize], &tmp) // E(0,i)
  390. xorBytes1x16(L[:], tmp[:], L[:blockSize])
  391. memwipe(buf[:blockSize])
  392. copy(buf[:], L[:(inBytes+1)/2])
  393. buf[inBytes/2] = (buf[inBytes/2] & mask) | pad
  394. xorBytes1x16(buf[:], delta[:], buf[:blockSize])
  395. buf[15] ^= byte(int(j) + step)
  396. e.aes.AES4(&zero, &e.I[1], &e.L[i], buf[:blockSize], &tmp) // E(0,i)
  397. xorBytes1x16(R[:], tmp[:], R[:blockSize])
  398. }
  399. copy(buf[:], R[:inBytes/2])
  400. copy(buf[inBytes/2:], L[:(inBytes+1)/2])
  401. if inBytes&1 != 0 {
  402. for k := inBytes - 1; k > inBytes/2; k-- {
  403. buf[k] = (buf[k] >> 4) | (buf[k-1] << 4)
  404. }
  405. buf[inBytes/2] = (L[0] >> 4) | (R[inBytes/2] & 0xf0)
  406. }
  407. copy(out, buf[:inBytes])
  408. if inBytes < 16 && d == 0 {
  409. memwipe(buf[inBytes:blockSize])
  410. buf[0] |= 0x80
  411. xorBytes1x16(delta[:], buf[:], buf[:blockSize])
  412. e.aes.AES4(&zero, &e.I[1], &e.L[3], buf[:blockSize], &tmp) // E(0,3)
  413. out[0] ^= tmp[0] & 0x80
  414. }
  415. memwipe(tmp[:])
  416. }
  417. func (e *eState) encipher(delta *[blockSize]byte, in, out []byte) {
  418. if len(in) == 0 {
  419. return
  420. }
  421. if len(in) < 32 {
  422. e.aezTiny(delta, in, 0, out)
  423. } else {
  424. e.aezCore(delta, in, 0, out)
  425. }
  426. }
  427. func (e *eState) decipher(delta *[blockSize]byte, in, out []byte) {
  428. if len(in) == 0 {
  429. return
  430. }
  431. if len(in) < 32 {
  432. e.aezTiny(delta, in, 1, out)
  433. } else {
  434. e.aezCore(delta, in, 1, out)
  435. }
  436. }
  437. // Encrypt encrypts and authenticates the plaintext, authenticates the
  438. // additional data, and appends the result to ciphertext, returning the
  439. // updated slice. The length of the authentication tag in bytes is specified
  440. // by tau. The plaintext and dst slices MUST NOT overlap.
  441. func Encrypt(key []byte, nonce []byte, additionalData [][]byte, tau int, plaintext, dst []byte) []byte {
  442. var delta [blockSize]byte
  443. var x []byte
  444. dstSz, xSz := len(dst), len(plaintext)+tau
  445. if cap(dst) >= dstSz+xSz {
  446. dst = dst[:dstSz+xSz]
  447. } else {
  448. x = make([]byte, dstSz+xSz)
  449. copy(x, dst)
  450. dst = x
  451. }
  452. x = dst[dstSz:]
  453. var e eState
  454. defer e.reset()
  455. e.init(key)
  456. e.aezHash(nonce, additionalData, tau*8, delta[:])
  457. if len(plaintext) == 0 {
  458. e.aezPRF(&delta, tau, x)
  459. } else {
  460. memwipe(x[len(plaintext):])
  461. copy(x, plaintext)
  462. e.encipher(&delta, x, x)
  463. }
  464. return dst
  465. }
  466. // Decrypt decrypts and authenticates the ciphertext, authenticates the
  467. // additional data, and if successful appends the resulting plaintext to the
  468. // provided slice and returns the updated slice and true. The length of the
  469. // expected authentication tag in bytes is specified by tau. The ciphertext
  470. // and dst slices MUST NOT overlap.
  471. func Decrypt(key []byte, nonce []byte, additionalData [][]byte, tau int, ciphertext, dst []byte) ([]byte, bool) {
  472. var delta [blockSize]byte
  473. sum := byte(0)
  474. if len(ciphertext) < tau {
  475. return nil, false
  476. }
  477. var x []byte
  478. dstSz, xSz := len(dst), len(ciphertext)
  479. if cap(dst) >= dstSz+xSz {
  480. dst = dst[:dstSz+xSz]
  481. } else {
  482. x = make([]byte, dstSz+xSz)
  483. copy(x, dst)
  484. dst = x
  485. }
  486. x = dst[dstSz:]
  487. var e eState
  488. defer e.reset()
  489. e.init(key)
  490. e.aezHash(nonce, additionalData, tau*8, delta[:])
  491. if len(ciphertext) == tau {
  492. e.aezPRF(&delta, tau, x)
  493. for i := 0; i < tau; i++ {
  494. sum |= x[i] ^ ciphertext[i]
  495. }
  496. dst = dst[:dstSz]
  497. } else {
  498. e.decipher(&delta, ciphertext, x)
  499. for i := 0; i < tau; i++ {
  500. sum |= x[len(ciphertext)-tau+i]
  501. }
  502. if sum == 0 {
  503. dst = dst[:dstSz+len(ciphertext)-tau]
  504. }
  505. }
  506. if sum != 0 { // return true if valid, false if invalid
  507. return nil, false
  508. }
  509. return dst, true
  510. }
  511. // IsHardwareAccelerated returns true iff the AEZ implementation will use
  512. // hardware acceleration (eg: AES-NI).
  513. func IsHardwareAccelerated() bool {
  514. return isHardwareAccelerated
  515. }
  516. func memwipe(b []byte) {
  517. for i := range b {
  518. b[i] = 0
  519. }
  520. }
  521. func xorBytes(a, b, dst []byte) {
  522. if len(a) < len(dst) || len(b) < len(dst) {
  523. panic("aez: xorBytes: len")
  524. }
  525. for i := 0; i < len(dst); i++ {
  526. dst[i] = a[i] ^ b[i]
  527. }
  528. }
  529. func swapBlocks(tmp *[blockSize]byte, b []byte) {
  530. copy(tmp[:], b[:])
  531. copy(b[:blockSize], b[blockSize:])
  532. copy(b[blockSize:], tmp[:])
  533. }
  534. func init() {
  535. // Pick the correct bitsliced round function based on target.
  536. //
  537. // Fucking appengine doesn't have `unsafe`, so derive based off uintptr.
  538. // It's retarded that this isn't a constant in runtime or something.
  539. maxUintptr := uint64(^uintptr(0))
  540. switch maxUintptr {
  541. case math.MaxUint32:
  542. newAes = newRoundB32
  543. case math.MaxUint64:
  544. newAes = newRoundB64
  545. default:
  546. panic("aez/init: unsupported pointer size")
  547. }
  548. // Attempt to detect hardware acceleration.
  549. platformInit()
  550. }