// XORKeyStream crypts bytes from src to dst. Src and dst may be the same slice // but otherwise should not overlap. If len(dst) < len(src) the function panics. func (c *Cipher) XORKeyStream(dst, src []byte) { length := len(src) if len(dst) < length { panic("chacha20/chacha: dst buffer is to small") } if c.off > 0 { n := crypto.XOR(dst, src, c.block[c.off:]) if n == length { c.off += n return } src = src[n:] dst = dst[n:] length -= n c.off = 0 } if length >= 64 { XORBlocks(dst, src, &(c.state), c.rounds) } if n := length & (^(64 - 1)); length-n > 0 { Core(&(c.block), &(c.state), c.rounds) c.off += crypto.XOR(dst[n:], src[n:], c.block[:]) } }
func (h *macFunc) Write(msg []byte) (int, error) { bs := h.BlockSize() n := len(msg) if h.off > 0 { dif := bs - h.off if n > dif { crypto.XOR(h.buf[h.off:], h.buf[h.off:], msg[:dif]) msg = msg[dif:] h.cipher.Encrypt(h.buf, h.buf) h.off = 0 } else { crypto.XOR(h.buf[h.off:], h.buf[h.off:], msg) h.off += n return n, nil } } if length := len(msg); length > bs { nn := length & (^(bs - 1)) if length == nn { nn -= bs } for i := 0; i < nn; i += bs { crypto.XOR(h.buf, h.buf, msg[i:i+bs]) h.cipher.Encrypt(h.buf, h.buf) } msg = msg[nn:] } if length := len(msg); length > 0 { crypto.XOR(h.buf[h.off:], h.buf[h.off:], msg) h.off += length } return n, nil }
// ctrCrypt encrypts the bytes in src with the CTR mode and writes // the ciphertext into dst func (c *eaxCipher) ctrCrypt(dst, src []byte) { length := len(src) bs := c.blockCipher.BlockSize() n := length & (^(length - bs)) for i := 0; i < n; i += bs { j := i + bs c.blockCipher.Encrypt(c.block, c.ctr) crypto.XOR(dst[i:j], src[i:j], c.block) // Increment counter for k := len(c.ctr) - 1; k >= 0; k-- { c.ctr[k]++ if c.ctr[k] != 0 { break } } } if n < length { c.blockCipher.Encrypt(c.block, c.ctr) crypto.XOR(dst[n:], src[n:], c.block) } // no reset of ctr needed - Seal or Open does this for us }
func (h *macFunc) Sum(b []byte) []byte { bs := h.cipher.BlockSize() // Don't change the buffer so the // caller can keep writing and suming. hash := make([]byte, bs) k := h.k0 if h.off < bs { k = h.k1 } crypto.XOR(hash, k, h.buf) if h.off < h.cipher.BlockSize() { hash[h.off] ^= 0x80 } h.cipher.Encrypt(hash, hash) return append(b, hash...) }
func (c *streamCipher) XORKeyStream(dst, src []byte) { length := len(src) if len(dst) < length { panic("dst buffer is to small") } if c.off > 0 { left := 4 - c.off if left > length { left = length } for i, v := range c.keyStream[c.off : c.off+left] { dst[i] = src[i] ^ v } src = src[left:] dst = dst[left:] length -= left c.off += left if c.off == 4 { c.off = 0 } } n := length - (length % 4) for i := 0; i < n; i += 4 { k := genKeyStream(&(c.ctr), &(c.p), &(c.q)) dst[i] = src[i] ^ byte(k) dst[i+1] = src[i+1] ^ byte(k>>8) dst[i+2] = src[i+2] ^ byte(k>>16) dst[i+3] = src[i+3] ^ byte(k>>24) } length -= n if length > 0 { k := genKeyStream(&(c.ctr), &(c.p), &(c.q)) c.keyStream[0] = byte(k) c.keyStream[1] = byte(k >> 8) c.keyStream[2] = byte(k >> 16) c.keyStream[3] = byte(k >> 24) c.off += crypto.XOR(dst[n:], src[n:], c.keyStream[:]) } }
// XORKeyStream crypts bytes from src to dst using the given key, nonce and counter. // The rounds argument specifies the number of rounds (must be even) performed for // keystream generation. (Common values are 20, 12 or 8) Src and dst may be the same // slice but otherwise should not overlap. If len(dst) < len(src) this function panics. func XORKeyStream(dst, src []byte, nonce *[12]byte, key *[32]byte, counter uint32, rounds int) { length := len(src) if len(dst) < length { panic("chacha20/chacha: dst buffer is to small") } if rounds <= 0 || rounds%2 != 0 { panic("chacha20/chacha: rounds must be a multiple of 2") } var state [64]byte copy(state[:], constants[:]) statePtr := (*[8]uint64)(unsafe.Pointer(&state[0])) keyPtr := (*[4]uint64)(unsafe.Pointer(&key[0])) statePtr[2] = keyPtr[0] statePtr[3] = keyPtr[1] statePtr[4] = keyPtr[2] statePtr[5] = keyPtr[3] statePtr[6] = (*(*uint64)(unsafe.Pointer(&nonce[0])) << 32) | uint64(counter) statePtr[7] = *(*uint64)(unsafe.Pointer(&nonce[4])) if length >= 64 { XORBlocks(dst, src, &state, rounds) } if n := length & (^(64 - 1)); length-n > 0 { var block [64]byte Core(&block, &state, rounds) crypto.XOR(dst[n:], src[n:], block[:]) } }