forked from External/grumble
pkg/cryptstate: make cryptstate independent of the chosen crypto mode.
This commit is contained in:
parent
154b7938d3
commit
56b174d983
3 changed files with 97 additions and 24 deletions
|
|
@ -6,7 +6,6 @@ package cryptstate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -16,6 +15,16 @@ import (
|
||||||
|
|
||||||
const DecryptHistorySize = 0x100
|
const DecryptHistorySize = 0x100
|
||||||
|
|
||||||
|
type CryptoMode interface {
|
||||||
|
NonceSize() int
|
||||||
|
KeySize() int
|
||||||
|
Overhead() int
|
||||||
|
|
||||||
|
SetKey([]byte)
|
||||||
|
Encrypt(dst []byte, src []byte, nonce []byte)
|
||||||
|
Decrypt(dst []byte, src []byte, nonce []byte) bool
|
||||||
|
}
|
||||||
|
|
||||||
type CryptState struct {
|
type CryptState struct {
|
||||||
Key []byte
|
Key []byte
|
||||||
EncryptIV []byte
|
EncryptIV []byte
|
||||||
|
|
@ -33,7 +42,7 @@ type CryptState struct {
|
||||||
RemoteResync uint32
|
RemoteResync uint32
|
||||||
|
|
||||||
decryptHistory [DecryptHistorySize]byte
|
decryptHistory [DecryptHistorySize]byte
|
||||||
cipher cipher.Block
|
mode CryptoMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupportedModes returns the list of supported CryptoModes.
|
// SupportedModes returns the list of supported CryptoModes.
|
||||||
|
|
@ -41,12 +50,23 @@ func SupportedModes() []string {
|
||||||
return []string{"OCB2-AES128"}
|
return []string{"OCB2-AES128"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createMode creates the CryptoMode with the given mode name.
|
||||||
|
func createMode(mode string) CryptoMode {
|
||||||
|
switch mode {
|
||||||
|
case "OCB2-AES128":
|
||||||
|
return &ocb2Mode{}
|
||||||
|
}
|
||||||
|
panic("cryptstate: no such CryptoMode")
|
||||||
|
}
|
||||||
|
|
||||||
func (cs *CryptState) GenerateKey() error {
|
func (cs *CryptState) GenerateKey() error {
|
||||||
cs.Key = make([]byte, aes.BlockSize)
|
cs.mode = createMode("OCB2-AES128")
|
||||||
|
cs.Key = make([]byte, cs.mode.KeySize())
|
||||||
_, err := io.ReadFull(rand.Reader, cs.Key)
|
_, err := io.ReadFull(rand.Reader, cs.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
cs.mode.SetKey(cs.Key)
|
||||||
|
|
||||||
cs.EncryptIV = make([]byte, ocb2.NonceSize)
|
cs.EncryptIV = make([]byte, ocb2.NonceSize)
|
||||||
_, err = io.ReadFull(rand.Reader, cs.EncryptIV)
|
_, err = io.ReadFull(rand.Reader, cs.EncryptIV)
|
||||||
|
|
@ -60,11 +80,6 @@ func (cs *CryptState) GenerateKey() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.cipher, err = aes.NewCipher(cs.Key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,8 +92,8 @@ func (cs *CryptState) SetKey(key []byte, eiv []byte, div []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cs.cipher = cipher
|
|
||||||
|
|
||||||
|
cs.mode = &ocb2Mode{cipher: cipher}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +108,6 @@ func (cs *CryptState) Decrypt(dst, src []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
ivbyte := src[0]
|
ivbyte := src[0]
|
||||||
tag := src[1:4]
|
|
||||||
restore := false
|
restore := false
|
||||||
lost := 0
|
lost := 0
|
||||||
late := 0
|
late := 0
|
||||||
|
|
@ -167,7 +181,7 @@ func (cs *CryptState) Decrypt(dst, src []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := ocb2.Decrypt(cs.cipher, dst, src[4:], cs.DecryptIV, tag[:])
|
ok := cs.mode.Decrypt(dst, src[1:], cs.DecryptIV)
|
||||||
if !ok {
|
if !ok {
|
||||||
cs.DecryptIV = saveiv
|
cs.DecryptIV = saveiv
|
||||||
return errors.New("cryptstate: tag mismatch")
|
return errors.New("cryptstate: tag mismatch")
|
||||||
|
|
@ -197,8 +211,6 @@ func (cs *CryptState) Decrypt(dst, src []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CryptState) Encrypt(dst, src []byte) {
|
func (cs *CryptState) Encrypt(dst, src []byte) {
|
||||||
var tag [ocb2.TagSize]byte
|
|
||||||
|
|
||||||
// First, increase our IV
|
// First, increase our IV
|
||||||
for i := range cs.EncryptIV {
|
for i := range cs.EncryptIV {
|
||||||
cs.EncryptIV[i] += 1
|
cs.EncryptIV[i] += 1
|
||||||
|
|
@ -207,12 +219,6 @@ func (cs *CryptState) Encrypt(dst, src []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ocb2.Encrypt(cs.cipher, dst[4:], src, cs.EncryptIV, tag[:])
|
|
||||||
|
|
||||||
dst[0] = cs.EncryptIV[0]
|
dst[0] = cs.EncryptIV[0]
|
||||||
dst[1] = tag[0]
|
cs.mode.Encrypt(dst[1:], src, cs.EncryptIV)
|
||||||
dst[2] = tag[1]
|
|
||||||
dst[3] = tag[2]
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
68
pkg/cryptstate/mode_ocb2.go
Normal file
68
pkg/cryptstate/mode_ocb2.go
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Copyright (c) 2012 The Grumble Authors
|
||||||
|
// The use of this source code is goverened by a BSD-style
|
||||||
|
// license that can be found in the LICENSE-file.
|
||||||
|
|
||||||
|
package cryptstate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"mumbleapp.com/grumble/pkg/cryptstate/ocb2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ocb2Mode implements the OCB2-AES128 CryptoMode
|
||||||
|
type ocb2Mode struct {
|
||||||
|
cipher cipher.Block
|
||||||
|
}
|
||||||
|
|
||||||
|
// NonceSize returns the nonce size to be used with OCB2-AES128.
|
||||||
|
func (ocb *ocb2Mode) NonceSize() int {
|
||||||
|
return ocb2.NonceSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeySize returns the key size to be used with OCB2-AES128.
|
||||||
|
func (ocb *ocb2Mode) KeySize() int {
|
||||||
|
return aes.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overhead returns the overhead that a ciphertext has over a plaintext.
|
||||||
|
// In the case of OCB2-AES128, the overhead is the authentication tag.
|
||||||
|
func (ocb *ocb2Mode) Overhead() int {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKey sets a new key. The key must have a length equal to KeySize().
|
||||||
|
func (ocb *ocb2Mode) SetKey(key []byte) {
|
||||||
|
if len(key) != ocb.KeySize() {
|
||||||
|
panic("cryptstate: invalid key length")
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
panic("cryptstate: NewCipher returned unexpected " + err.Error())
|
||||||
|
}
|
||||||
|
ocb.cipher = cipher
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt encrypts a message using OCB2-AES128 and outputs it to dst.
|
||||||
|
func (ocb *ocb2Mode) Encrypt(dst []byte, src []byte, nonce []byte) {
|
||||||
|
if len(dst) <= ocb.Overhead() {
|
||||||
|
panic("cryptstate: bad dst")
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := dst[0:3]
|
||||||
|
dst = dst[3:]
|
||||||
|
ocb2.Encrypt(ocb.cipher, dst, src, nonce, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypts a message using OCB2-AES128 and outputs it to dst.
|
||||||
|
// Returns false if decryption failed (authentication tag mismatch).
|
||||||
|
func (ocb *ocb2Mode) Decrypt(dst []byte, src []byte, nonce []byte) bool {
|
||||||
|
if len(src) <= ocb.Overhead() {
|
||||||
|
panic("cryptstate: bad src")
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := src[0:3]
|
||||||
|
src = src[3:]
|
||||||
|
return ocb2.Decrypt(ocb.cipher, dst, src, nonce, tag)
|
||||||
|
}
|
||||||
|
|
@ -119,15 +119,13 @@ func Encrypt(cipher cipher.Block, dst []byte, src []byte, nonce []byte, tag []by
|
||||||
if len(nonce) != NonceSize {
|
if len(nonce) != NonceSize {
|
||||||
panic("ocb2: nonce length is not equal to ocb2.NonceSize")
|
panic("ocb2: nonce length is not equal to ocb2.NonceSize")
|
||||||
}
|
}
|
||||||
if len(tag) != TagSize {
|
|
||||||
panic("ocb2: tag length is not equal to ocb2.TagSize")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
checksum [BlockSize]byte
|
checksum [BlockSize]byte
|
||||||
delta [BlockSize]byte
|
delta [BlockSize]byte
|
||||||
tmp [BlockSize]byte
|
tmp [BlockSize]byte
|
||||||
pad [BlockSize]byte
|
pad [BlockSize]byte
|
||||||
|
calcTag [NonceSize]byte
|
||||||
off int
|
off int
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -167,7 +165,8 @@ func Encrypt(cipher cipher.Block, dst []byte, src []byte, nonce []byte, tag []by
|
||||||
|
|
||||||
times3(delta[0:])
|
times3(delta[0:])
|
||||||
xor(tmp[0:], delta[0:], checksum[0:])
|
xor(tmp[0:], delta[0:], checksum[0:])
|
||||||
cipher.Encrypt(tag[0:], tmp[0:])
|
cipher.Encrypt(calcTag[0:], tmp[0:])
|
||||||
|
copy(tag, calcTag[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt takes a ciphertext, a nonce, and a tag as its input and outputs a decrypted
|
// Decrypt takes a ciphertext, a nonce, and a tag as its input and outputs a decrypted
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue