// Generate a psuedorandom 32-byte mask and put it in mask. mask must be // zeroes when this is called. func generateMask(mask []byte) { var nonce [16]byte newCounter := atomic.AddUint64(&counter, 1) binary.LittleEndian.PutUint64(nonce[0:8], newCounter) salsa.XORKeyStream(mask[0:32], mask[0:32], &nonce, &randKey) }
func (c *salsaStreamCipher) XORKeyStream(dst, src []byte) { var buf []byte padLen := c.counter % 64 dataSize := len(src) + padLen if cap(dst) >= dataSize { buf = dst[:dataSize] } else if leakyBufSize >= dataSize { buf = leakyBuf.Get() defer leakyBuf.Put(buf) buf = buf[:dataSize] } else { buf = make([]byte, dataSize) } var subNonce [16]byte copy(subNonce[:], c.nonce[:]) binary.LittleEndian.PutUint64(subNonce[len(c.nonce):], uint64(c.counter/64)) // It's difficult to avoid data copy here. src or dst maybe slice from // Conn.Read/Write, which can't have padding. copy(buf[padLen:], src[:]) salsa.XORKeyStream(buf, buf, &subNonce, &c.key) copy(dst, buf[padLen:]) c.counter += len(src) }
// Open authenticates and decrypts a box produced by Seal and appends the // message to out, which must not overlap box. The output will be Overhead // bytes smaller than box. func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) { if len(box) < Overhead { return nil, false } var subKey [32]byte var counter [16]byte setup(&subKey, &counter, nonce, key) // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since // Salsa20 works with 64-byte blocks, we also generate 32 bytes of // keystream as a side effect. var firstBlock [64]byte salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey) var poly1305Key [32]byte copy(poly1305Key[:], firstBlock[:]) var tag [poly1305.TagSize]byte copy(tag[:], box) if !poly1305.Verify(&tag, box[poly1305.TagSize:], &poly1305Key) { return nil, false } ret, out := sliceForAppend(out, len(box)-Overhead) // We XOR up to 32 bytes of box with the keystream generated from // the first block. box = box[Overhead:] firstMessageBlock := box if len(firstMessageBlock) > 32 { firstMessageBlock = firstMessageBlock[:32] } for i, x := range firstMessageBlock { out[i] = firstBlock[32+i] ^ x } box = box[len(firstMessageBlock):] out = out[len(firstMessageBlock):] // Now decrypt the rest. counter[8] = 1 salsa.XORKeyStream(out, box, &counter, &subKey) return ret, true }
// Seal appends an encrypted and authenticated copy of message to out, which // must not overlap message. The key and nonce pair must be unique for each // distinct message and the output will be Overhead bytes longer than message. func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte { var subKey [32]byte var counter [16]byte setup(&subKey, &counter, nonce, key) // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since // Salsa20 works with 64-byte blocks, we also generate 32 bytes of // keystream as a side effect. var firstBlock [64]byte salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey) var poly1305Key [32]byte copy(poly1305Key[:], firstBlock[:]) ret, out := sliceForAppend(out, len(message)+poly1305.TagSize) // We XOR up to 32 bytes of message with the keystream generated from // the first block. firstMessageBlock := message if len(firstMessageBlock) > 32 { firstMessageBlock = firstMessageBlock[:32] } tagOut := out out = out[poly1305.TagSize:] for i, x := range firstMessageBlock { out[i] = firstBlock[32+i] ^ x } message = message[len(firstMessageBlock):] ciphertext := out out = out[len(firstMessageBlock):] // Now encrypt the rest. counter[8] = 1 salsa.XORKeyStream(out, message, &counter, &subKey) var tag [poly1305.TagSize]byte poly1305.Sum(&tag, ciphertext, &poly1305Key) copy(tagOut, tag[:]) return ret }
func GetCSPNonce(req *http.Request) string { v, ok := context.Get(req, &cspNonceKey).(string) if ok { return v } var b [8]byte var nonce [16]byte binary.LittleEndian.PutUint64(nonce[0:8], atomic.AddUint64(&cspNonceCounter, 1)) salsa.XORKeyStream(b[:], b[:], &nonce, &cspNonceGenerationKey) v = base64.RawURLEncoding.EncodeToString(b[:]) context.Set(req, &cspNonceKey, v) return v }
// XORKeyStream crypts bytes from in to out using the given key and nonce. In // and out may be the same slice but otherwise should not overlap. Nonce must // be either 8 or 24 bytes long. func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte) { if len(out) < len(in) { in = in[:len(out)] } var subNonce [16]byte if len(nonce) == 24 { var subKey [32]byte var hNonce [16]byte copy(hNonce[:], nonce[:16]) salsa.HSalsa20(&subKey, &hNonce, key, &salsa.Sigma) copy(subNonce[:], nonce[16:]) key = &subKey } else if len(nonce) == 8 { copy(subNonce[:], nonce[:]) } else { panic("salsa20: nonce must be 8 or 24 bytes") } salsa.XORKeyStream(out, in, &subNonce, key) }
func (c *salsaStreamCipher) XORKeyStream(dst, src []byte) { var buf []byte padLen := c.counter % 64 dataSize := len(src) + padLen if cap(dst) >= dataSize { buf = dst[:dataSize] } else if leakyBufSize >= dataSize { buf = leakyBuf.Get() defer leakyBuf.Put(buf) buf = buf[:dataSize] } else { buf = make([]byte, dataSize) } var subNonce [16]byte copy(subNonce[:], c.nonce[:]) binary.LittleEndian.PutUint64(subNonce[len(c.nonce):], uint64(c.counter/64)) copy(buf[padLen:], src[:]) salsa.XORKeyStream(buf, buf, &subNonce, &c.key) copy(dst, buf[padLen:]) c.counter += len(src) }