Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/grumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorMikkel Krautz <mikkel@krautz.dk>2012-12-09 01:56:05 +0400
committerMikkel Krautz <mikkel@krautz.dk>2012-12-09 01:56:05 +0400
commit154b7938d3c68cb395401eb72cab00a33ccd30fd (patch)
tree10ed954476f8fad75e3595013c9163edbb05fc4a /pkg
parent2b12adc014f3d1e4342f648584390a515f0114c7 (diff)
pkg/cryptstate, pkg/cryptstate/ocb2: move OCB2 tag verification into ocb2.Decrypt.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/cryptstate/cryptstate.go13
-rw-r--r--pkg/cryptstate/ocb2/ocb2.go484
-rw-r--r--pkg/cryptstate/ocb2/ocb2_test.go406
3 files changed, 453 insertions, 450 deletions
diff --git a/pkg/cryptstate/cryptstate.go b/pkg/cryptstate/cryptstate.go
index c4bca38..2fb4434 100644
--- a/pkg/cryptstate/cryptstate.go
+++ b/pkg/cryptstate/cryptstate.go
@@ -92,8 +92,8 @@ func (cs *CryptState) Decrypt(dst, src []byte) error {
return errors.New("cryptstate: plain_len and src len mismatch")
}
- var tag [ocb2.TagSize]byte
ivbyte := src[0]
+ tag := src[1:4]
restore := false
lost := 0
late := 0
@@ -167,13 +167,10 @@ func (cs *CryptState) Decrypt(dst, src []byte) error {
}
}
- ocb2.Decrypt(cs.cipher, dst, src[4:], cs.DecryptIV, tag[:])
-
- for i := 0; i < 3; i++ {
- if tag[i] != src[i+1] {
- cs.DecryptIV = saveiv
- return errors.New("tag mismatch")
- }
+ ok := ocb2.Decrypt(cs.cipher, dst, src[4:], cs.DecryptIV, tag[:])
+ if !ok {
+ cs.DecryptIV = saveiv
+ return errors.New("cryptstate: tag mismatch")
}
cs.decryptHistory[cs.DecryptIV[0]] = cs.DecryptIV[0]
diff --git a/pkg/cryptstate/ocb2/ocb2.go b/pkg/cryptstate/ocb2/ocb2.go
index 55e45a0..55c7438 100644
--- a/pkg/cryptstate/ocb2/ocb2.go
+++ b/pkg/cryptstate/ocb2/ocb2.go
@@ -1,237 +1,247 @@
-// Copyright (c) 2010-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 ocb2 implements the version 2 of the OCB authenticated-encryption algorithm.
-// OCB2 is specified in http://www.cs.ucdavis.edu/~rogaway/papers/draft-krovetz-ocb-00.txt.
-//
-// Note that this implementation is limited to block ciphers with a block size of 128 bits.
-//
-// It should also be noted that OCB's author, Phil Rogaway <rogaway@cs.ucdavis.edu>, holds
-// several US patents on the algorithm. This should be considered before using this code
-// in your own projects. See OCB's FAQ for more info:
-// http://www.cs.ucdavis.edu/~rogaway/ocb/ocb-faq.htm#patent:phil
-//
-// The Mumble Project has a license to use OCB mode in its BSD licensed code on a royalty
-// free basis.
-package ocb2
-
-import "crypto/cipher"
-
-const (
- // BlockSize defines the block size that this particular implementation
- // of OCB2 is made to work on.
- BlockSize = 16
- // TagSize specifies the length in bytes of a full OCB2 tag.
- // As per the specification, applications may truncate their
- // tags to a given length, but advocates that typical applications
- // should use a tag length of at least 8 bytes (64 bits).
- TagSize = BlockSize
- // NonceSize specifies the length in bytes of an OCB2 nonce.
- NonceSize = BlockSize
-)
-
-// zeros fills block with zero bytes.
-func zeros(block []byte) {
- for i := range block {
- block[i] = 0
- }
-}
-
-// xor outputs the bitwise exclusive-or of a and b to dst.
-func xor(dst []byte, a []byte, b []byte) {
- for i := 0; i < BlockSize; i++ {
- dst[i] = a[i] ^ b[i]
- }
-}
-
-// times2 performs the times2 operation, defined as:
-//
-// times2(S)
-// S << 1 if S[1] = 0, and (S << 1) xor const(bitlength(S)) if S[1] = 1.
-//
-// where const(n) is defined as
-//
-// const(n)
-// The lexicographically first n-bit string C among all
-// strings that have a minimal possible number of "1"
-// bits and which name a polynomial x^n + C[1] *
-// x^{n-1} + ... + C[n-1] * x^1 + C[n] * x^0 that is
-// irreducible over the field with two elements. In
-// particular, const(128) = num2str(135, 128). For
-// other values of n, refer to a standard table of
-// irreducible polynomials [G. Seroussi,
-// "Table of low-weight binary irreducible polynomials",
-// HP Labs Technical Report HPL-98-135, 1998.].
-//
-// and num2str(x, n) is defined as
-//
-// num2str(x, n)
-// The n-bit binary representation of the integer x.
-// More formally, the n-bit string S where x = S[1] *
-// 2^{n-1} + S[2] * 2^{n-2} + ... + S[n] * 2^{0}. Only
-// used when 0 <= x < 2^n.
-//
-// For our 128-bit block size implementation, this means that
-// the xor with const(bitlength(S)) if S[1] = 1 is implemented
-// by simply xor'ing the last byte with the number 135 when
-// S[1] = 1.
-func times2(block []byte) {
- carry := (block[0] >> 7) & 0x1
- for i := 0; i < BlockSize-1; i++ {
- block[i] = (block[i] << 1) | ((block[i+1] >> 7) & 0x1)
- }
- block[BlockSize-1] = (block[BlockSize-1] << 1) ^ (carry * 135)
-}
-
-// times3 performs the times3 operation, defined as:
-//
-// times3(S)
-// times2(S) xor S
-func times3(block []byte) {
- carry := (block[0] >> 7) & 0x1
- for i := 0; i < BlockSize-1; i++ {
- block[i] ^= (block[i] << 1) | ((block[i+1] >> 7) & 0x1)
- }
- block[BlockSize-1] ^= ((block[BlockSize-1] << 1) ^ (carry * 135))
-}
-
-// Encrypt encrypts the plaintext src and outputs the corresponding ciphertext into dst.
-// Besides outputting a ciphertext into dst, Encrypt also outputs an authentication tag
-// of ocb2.TagSize bytes into tag, which should be used to verify the authenticity of the
-// message on the receiving side.
-//
-// To ensure both authenticity and secrecy of messages, each invocation to this function must
-// be given an unique nonce of ocb2.NonceSize bytes. The nonce need not be secret (it can be
-// a counter), but it needs to be unique.
-//
-// The block cipher used in function must work on a block size equal to ocb2.BlockSize.
-// The tag slice used in this function must have a length equal to ocb2.TagSize.
-// The nonce slice used in this function must have a length equal to ocb2.NonceSize.
-// If any of the above are violated, Encrypt will panic.
-func Encrypt(cipher cipher.Block, dst []byte, src []byte, nonce []byte, tag []byte) {
- if cipher.BlockSize() != BlockSize {
- panic("ocb2: cipher blocksize is not equal to ocb2.BlockSize")
- }
- if len(nonce) != 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 (
- checksum [BlockSize]byte
- delta [BlockSize]byte
- tmp [BlockSize]byte
- pad [BlockSize]byte
- off int
- )
-
- cipher.Encrypt(delta[0:], nonce[0:])
- zeros(checksum[0:])
-
- remain := len(src)
- for remain > BlockSize {
- times2(delta[0:])
- xor(tmp[0:], delta[0:], src[off:off+BlockSize])
- cipher.Encrypt(tmp[0:], tmp[0:])
- xor(dst[off:off+BlockSize], delta[0:], tmp[0:])
- xor(checksum[0:], checksum[0:], src[off:off+BlockSize])
- remain -= BlockSize
- off += BlockSize
- }
-
- times2(delta[0:])
- zeros(tmp[0:])
- num := remain * 8
- tmp[BlockSize-2] = uint8((uint32(num) >> 8) & 0xff)
- tmp[BlockSize-1] = uint8(num & 0xff)
- xor(tmp[0:], tmp[0:], delta[0:])
- cipher.Encrypt(pad[0:], tmp[0:])
- copied := copy(tmp[0:], src[off:])
- if copied != remain {
- panic("ocb2: copy failed")
- }
- if copy(tmp[copied:], pad[copied:]) != (BlockSize - remain) {
- panic("ocb2: copy failed")
- }
- xor(checksum[0:], checksum[0:], tmp[0:])
- xor(tmp[0:], pad[0:], tmp[0:])
- if copy(dst[off:], tmp[0:]) != remain {
- panic("ocb2: copy failed")
- }
-
- times3(delta[0:])
- xor(tmp[0:], delta[0:], checksum[0:])
- cipher.Encrypt(tag[0:], tmp[0:])
-}
-
-// Decrypt takes a ciphertext and a nonce as its input and outputs a decrypted plaintext
-// and corresponding authentication tag.
-//
-// Before using the decrpyted plaintext, the application
-// should verify that the computed authentication tag matches the tag that was produced when
-// encrypting the message (taking into consideration that OCB tags are allowed to be truncated
-// to a length less than ocb.TagSize).
-//
-// The block cipher used in function must work on a block size equal to ocb2.BlockSize.
-// The tag slice used in this function must have a length equal to ocb2.TagSize.
-// The nonce slice used in this function must have a length equal to ocb2.NonceSize.
-// If any of the above are violated, Encrypt will panic.
-func Decrypt(cipher cipher.Block, plain []byte, encrypted []byte, nonce []byte, tag []byte) {
- if cipher.BlockSize() != BlockSize {
- panic("ocb2: cipher blocksize is not equal to ocb2.BlockSize")
- }
- if len(nonce) != 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 (
- checksum [BlockSize]byte
- delta [BlockSize]byte
- tmp [BlockSize]byte
- pad [BlockSize]byte
- off int
- )
-
- cipher.Encrypt(delta[0:], nonce[0:])
- zeros(checksum[0:])
-
- remain := len(encrypted)
- for remain > BlockSize {
- times2(delta[0:])
- xor(tmp[0:], delta[0:], encrypted[off:off+BlockSize])
- cipher.Decrypt(tmp[0:], tmp[0:])
- xor(plain[off:off+BlockSize], delta[0:], tmp[0:])
- xor(checksum[0:], checksum[0:], plain[off:off+BlockSize])
- off += BlockSize
- remain -= BlockSize
- }
-
- times2(delta[0:])
- zeros(tmp[0:])
- num := remain * 8
- tmp[BlockSize-2] = uint8((uint32(num) >> 8) & 0xff)
- tmp[BlockSize-1] = uint8(num & 0xff)
- xor(tmp[0:], tmp[0:], delta[0:])
- cipher.Encrypt(pad[0:], tmp[0:])
- zeros(tmp[0:])
- copied := copy(tmp[0:remain], encrypted[off:off+remain])
- if copied != remain {
- panic("ocb2: copy failed")
- }
- xor(tmp[0:], tmp[0:], pad[0:])
- xor(checksum[0:], checksum[0:], tmp[0:])
- copied = copy(plain[off:off+remain], tmp[0:remain])
- if copied != remain {
- panic("ocb2: copy failed")
- }
-
- times3(delta[0:])
- xor(tmp[0:], delta[0:], checksum[0:])
- cipher.Encrypt(tag[0:], tmp[0:])
-} \ No newline at end of file
+// Copyright (c) 2010-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 ocb2 implements the version 2 of the OCB authenticated-encryption algorithm.
+// OCB2 is specified in http://www.cs.ucdavis.edu/~rogaway/papers/draft-krovetz-ocb-00.txt.
+//
+// Note that this implementation is limited to block ciphers with a block size of 128 bits.
+//
+// It should also be noted that OCB's author, Phil Rogaway <rogaway@cs.ucdavis.edu>, holds
+// several US patents on the algorithm. This should be considered before using this code
+// in your own projects. See OCB's FAQ for more info:
+// http://www.cs.ucdavis.edu/~rogaway/ocb/ocb-faq.htm#patent:phil
+//
+// The Mumble Project has a license to use OCB mode in its BSD licensed code on a royalty
+// free basis.
+package ocb2
+
+import (
+ "crypto/cipher"
+ "crypto/subtle"
+)
+
+const (
+ // BlockSize defines the block size that this particular implementation
+ // of OCB2 is made to work on.
+ BlockSize = 16
+ // TagSize specifies the length in bytes of a full OCB2 tag.
+ // As per the specification, applications may truncate their
+ // tags to a given length, but advocates that typical applications
+ // should use a tag length of at least 8 bytes (64 bits).
+ TagSize = BlockSize
+ // NonceSize specifies the length in bytes of an OCB2 nonce.
+ NonceSize = BlockSize
+)
+
+// zeros fills block with zero bytes.
+func zeros(block []byte) {
+ for i := range block {
+ block[i] = 0
+ }
+}
+
+// xor outputs the bitwise exclusive-or of a and b to dst.
+func xor(dst []byte, a []byte, b []byte) {
+ for i := 0; i < BlockSize; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+}
+
+// times2 performs the times2 operation, defined as:
+//
+// times2(S)
+// S << 1 if S[1] = 0, and (S << 1) xor const(bitlength(S)) if S[1] = 1.
+//
+// where const(n) is defined as
+//
+// const(n)
+// The lexicographically first n-bit string C among all
+// strings that have a minimal possible number of "1"
+// bits and which name a polynomial x^n + C[1] *
+// x^{n-1} + ... + C[n-1] * x^1 + C[n] * x^0 that is
+// irreducible over the field with two elements. In
+// particular, const(128) = num2str(135, 128). For
+// other values of n, refer to a standard table of
+// irreducible polynomials [G. Seroussi,
+// "Table of low-weight binary irreducible polynomials",
+// HP Labs Technical Report HPL-98-135, 1998.].
+//
+// and num2str(x, n) is defined as
+//
+// num2str(x, n)
+// The n-bit binary representation of the integer x.
+// More formally, the n-bit string S where x = S[1] *
+// 2^{n-1} + S[2] * 2^{n-2} + ... + S[n] * 2^{0}. Only
+// used when 0 <= x < 2^n.
+//
+// For our 128-bit block size implementation, this means that
+// the xor with const(bitlength(S)) if S[1] = 1 is implemented
+// by simply xor'ing the last byte with the number 135 when
+// S[1] = 1.
+func times2(block []byte) {
+ carry := (block[0] >> 7) & 0x1
+ for i := 0; i < BlockSize-1; i++ {
+ block[i] = (block[i] << 1) | ((block[i+1] >> 7) & 0x1)
+ }
+ block[BlockSize-1] = (block[BlockSize-1] << 1) ^ (carry * 135)
+}
+
+// times3 performs the times3 operation, defined as:
+//
+// times3(S)
+// times2(S) xor S
+func times3(block []byte) {
+ carry := (block[0] >> 7) & 0x1
+ for i := 0; i < BlockSize-1; i++ {
+ block[i] ^= (block[i] << 1) | ((block[i+1] >> 7) & 0x1)
+ }
+ block[BlockSize-1] ^= ((block[BlockSize-1] << 1) ^ (carry * 135))
+}
+
+// Encrypt encrypts the plaintext src and outputs the corresponding ciphertext into dst.
+// Besides outputting a ciphertext into dst, Encrypt also outputs an authentication tag
+// of ocb2.TagSize bytes into tag, which should be used to verify the authenticity of the
+// message on the receiving side.
+//
+// To ensure both authenticity and secrecy of messages, each invocation to this function must
+// be given an unique nonce of ocb2.NonceSize bytes. The nonce need not be secret (it can be
+// a counter), but it needs to be unique.
+//
+// The block cipher used in function must work on a block size equal to ocb2.BlockSize.
+// The tag slice used in this function must have a length equal to ocb2.TagSize.
+// The nonce slice used in this function must have a length equal to ocb2.NonceSize.
+// If any of the above are violated, Encrypt will panic.
+func Encrypt(cipher cipher.Block, dst []byte, src []byte, nonce []byte, tag []byte) {
+ if cipher.BlockSize() != BlockSize {
+ panic("ocb2: cipher blocksize is not equal to ocb2.BlockSize")
+ }
+ if len(nonce) != 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 (
+ checksum [BlockSize]byte
+ delta [BlockSize]byte
+ tmp [BlockSize]byte
+ pad [BlockSize]byte
+ off int
+ )
+
+ cipher.Encrypt(delta[0:], nonce[0:])
+ zeros(checksum[0:])
+
+ remain := len(src)
+ for remain > BlockSize {
+ times2(delta[0:])
+ xor(tmp[0:], delta[0:], src[off:off+BlockSize])
+ cipher.Encrypt(tmp[0:], tmp[0:])
+ xor(dst[off:off+BlockSize], delta[0:], tmp[0:])
+ xor(checksum[0:], checksum[0:], src[off:off+BlockSize])
+ remain -= BlockSize
+ off += BlockSize
+ }
+
+ times2(delta[0:])
+ zeros(tmp[0:])
+ num := remain * 8
+ tmp[BlockSize-2] = uint8((uint32(num) >> 8) & 0xff)
+ tmp[BlockSize-1] = uint8(num & 0xff)
+ xor(tmp[0:], tmp[0:], delta[0:])
+ cipher.Encrypt(pad[0:], tmp[0:])
+ copied := copy(tmp[0:], src[off:])
+ if copied != remain {
+ panic("ocb2: copy failed")
+ }
+ if copy(tmp[copied:], pad[copied:]) != (BlockSize - remain) {
+ panic("ocb2: copy failed")
+ }
+ xor(checksum[0:], checksum[0:], tmp[0:])
+ xor(tmp[0:], pad[0:], tmp[0:])
+ if copy(dst[off:], tmp[0:]) != remain {
+ panic("ocb2: copy failed")
+ }
+
+ times3(delta[0:])
+ xor(tmp[0:], delta[0:], checksum[0:])
+ cipher.Encrypt(tag[0:], tmp[0:])
+}
+
+// Decrypt takes a ciphertext, a nonce, and a tag as its input and outputs a decrypted
+// plaintext (if successful) and a boolean flag that determines whether the function
+// successfully decrypted the given ciphertext.
+//
+// Before using the decrpyted plaintext, the application
+// should verify that the computed authentication tag matches the tag that was produced when
+// encrypting the message (taking into consideration that OCB tags are allowed to be truncated
+// to a length less than ocb.TagSize).
+//
+// The block cipher used in function must work on a block size equal to ocb2.BlockSize.
+// The tag slice used in this function must have a length equal to ocb2.TagSize.
+// The nonce slice used in this function must have a length equal to ocb2.NonceSize.
+// If any of the above are violated, Encrypt will panic.
+func Decrypt(cipher cipher.Block, plain []byte, encrypted []byte, nonce []byte, tag []byte) bool {
+ if cipher.BlockSize() != BlockSize {
+ panic("ocb2: cipher blocksize is not equal to ocb2.BlockSize")
+ }
+ if len(nonce) != NonceSize {
+ panic("ocb2: nonce length is not equal to ocb2.NonceSize")
+ }
+
+ var (
+ checksum [BlockSize]byte
+ delta [BlockSize]byte
+ tmp [BlockSize]byte
+ pad [BlockSize]byte
+ calcTag [NonceSize]byte
+ off int
+ )
+
+ cipher.Encrypt(delta[0:], nonce[0:])
+ zeros(checksum[0:])
+
+ remain := len(encrypted)
+ for remain > BlockSize {
+ times2(delta[0:])
+ xor(tmp[0:], delta[0:], encrypted[off:off+BlockSize])
+ cipher.Decrypt(tmp[0:], tmp[0:])
+ xor(plain[off:off+BlockSize], delta[0:], tmp[0:])
+ xor(checksum[0:], checksum[0:], plain[off:off+BlockSize])
+ off += BlockSize
+ remain -= BlockSize
+ }
+
+ times2(delta[0:])
+ zeros(tmp[0:])
+ num := remain * 8
+ tmp[BlockSize-2] = uint8((uint32(num) >> 8) & 0xff)
+ tmp[BlockSize-1] = uint8(num & 0xff)
+ xor(tmp[0:], tmp[0:], delta[0:])
+ cipher.Encrypt(pad[0:], tmp[0:])
+ zeros(tmp[0:])
+ copied := copy(tmp[0:remain], encrypted[off:off+remain])
+ if copied != remain {
+ panic("ocb2: copy failed")
+ }
+ xor(tmp[0:], tmp[0:], pad[0:])
+ xor(checksum[0:], checksum[0:], tmp[0:])
+ copied = copy(plain[off:off+remain], tmp[0:remain])
+ if copied != remain {
+ panic("ocb2: copy failed")
+ }
+
+ times3(delta[0:])
+ xor(tmp[0:], delta[0:], checksum[0:])
+ cipher.Encrypt(calcTag[0:], tmp[0:])
+
+ // Compare the calculated tag with the expected tag. Truncate
+ // the computed tag if necessary.
+ if subtle.ConstantTimeCompare(calcTag[:len(tag)], tag) != 1 {
+ return false
+ }
+
+ return true
+}
diff --git a/pkg/cryptstate/ocb2/ocb2_test.go b/pkg/cryptstate/ocb2/ocb2_test.go
index d72d762..0c9bfcc 100644
--- a/pkg/cryptstate/ocb2/ocb2_test.go
+++ b/pkg/cryptstate/ocb2/ocb2_test.go
@@ -1,205 +1,201 @@
-// Copyright (c) 2010-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 ocb2
-
-import (
- "bytes"
- "crypto/aes"
- "encoding/hex"
- "testing"
-)
-
-func MustDecodeHex(s string) []byte {
- buf, err := hex.DecodeString(s)
- if err != nil {
- panic("MustDecodeHex: " + err.Error())
- }
- return buf
-}
-
-type ocbVector struct {
- Name string
- Key string
- Nonce string
- Header string
- PlainText string
- CipherText string
- Tag string
-}
-
-func (v ocbVector) KeyBytes() []byte {
- return MustDecodeHex(v.Key)
-}
-
-func (v ocbVector) NonceBytes() []byte {
- return MustDecodeHex(v.Nonce)
-}
-
-func (v ocbVector) PlainTextBytes() []byte {
- return MustDecodeHex(v.PlainText)
-}
-
-func (v ocbVector) CipherTextBytes() []byte {
- return MustDecodeHex(v.CipherText)
-}
-
-func (v ocbVector) TagBytes() []byte {
- return MustDecodeHex(v.Tag)
-}
-
-// ocb128Vectors are the test vectors for OCB-AES128 from
-// http://www.cs.ucdavis.edu/~rogaway/papers/draft-krovetz-ocb-00.txt
-//
-// Note: currently, the vectors with headers are not included in this list
-// as this implementation does not implement header authentication.
-var ocb128Vectors = []ocbVector{
- {
- Name: "OCB2-AES-128-001",
- Key: "000102030405060708090A0B0C0D0E0F",
- Nonce: "000102030405060708090A0B0C0D0E0F",
- PlainText: "",
- CipherText: "",
- Tag: "BF3108130773AD5EC70EC69E7875A7B0",
- },
- {
- Name: "OCB2-AES-128-002",
- Key: "000102030405060708090A0B0C0D0E0F",
- Nonce: "000102030405060708090A0B0C0D0E0F",
- PlainText: "0001020304050607",
- CipherText: "C636B3A868F429BB",
- Tag: "A45F5FDEA5C088D1D7C8BE37CABC8C5C",
- },
- {
- Name: "OCB2-AES-128-003",
- Key: "000102030405060708090A0B0C0D0E0F",
- Nonce: "000102030405060708090A0B0C0D0E0F",
- PlainText: "000102030405060708090A0B0C0D0E0F",
- CipherText: "52E48F5D19FE2D9869F0C4A4B3D2BE57",
- Tag: "F7EE49AE7AA5B5E6645DB6B3966136F9",
- },
- {
- Name: "OCB2-AES-128-003",
- Key: "000102030405060708090A0B0C0D0E0F",
- Nonce: "000102030405060708090A0B0C0D0E0F",
- PlainText: "000102030405060708090A0B0C0D0E0F1011121314151617",
- CipherText: "F75D6BC8B4DC8D66B836A2B08B32A636CC579E145D323BEB",
- Tag: "A1A50F822819D6E0A216784AC24AC84C",
- },
- {
- Name: "OCB2-AES-128-004",
- Key: "000102030405060708090A0B0C0D0E0F",
- Nonce: "000102030405060708090A0B0C0D0E0F",
- PlainText: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
- CipherText: "F75D6BC8B4DC8D66B836A2B08B32A636CEC3C555037571709DA25E1BB0421A27",
- Tag: "09CA6C73F0B5C6C5FD587122D75F2AA3",
- },
- {
- Name: "OCB2-AES-128-005",
- Key: "000102030405060708090A0B0C0D0E0F",
- Nonce: "000102030405060708090A0B0C0D0E0F",
- PlainText: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
- CipherText: "F75D6BC8B4DC8D66B836A2B08B32A6369F1CD3C5228D79FD6C267F5F6AA7B231C7DFB9D59951AE9C",
- Tag: "9DB0CDF880F73E3E10D4EB3217766688",
- },
-}
-
-func TestTimes2(t *testing.T) {
- msg := [aes.BlockSize]byte{
- 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- }
- expected := [aes.BlockSize]byte{
- 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b,
- }
-
- times2(msg[0:])
- if !bytes.Equal(msg[0:], expected[0:]) {
- t.Fatalf("times2 produces invalid output: %v, expected: %v", msg, expected)
- }
-}
-
-func TestTimes3(t *testing.T) {
- msg := [aes.BlockSize]byte{
- 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- }
- expected := [aes.BlockSize]byte{
- 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85,
- }
-
- times3(msg[0:])
- if !bytes.Equal(msg[0:], expected[0:]) {
- t.Errorf("times3 produces invalid output: %v, expected: %v", msg, expected)
- }
-}
-
-func TestZeros(t *testing.T) {
- var msg [aes.BlockSize]byte
- zeros(msg[0:])
- for i := 0; i < len(msg); i++ {
- if msg[i] != 0 {
- t.Fatalf("zeros does not zero slice.")
- }
- }
-}
-
-func TestXor(t *testing.T) {
- msg := [aes.BlockSize]byte{
- 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- }
- var out [aes.BlockSize]byte
- xor(out[0:], msg[0:], msg[0:])
- for i := 0; i < len(out); i++ {
- if out[i] != 0 {
- t.Fatalf("XOR broken")
- }
- }
-}
-
-func TestEncryptOCBAES128Vectors(t *testing.T) {
- for _, vector := range ocb128Vectors {
- cipher, err := aes.NewCipher(vector.KeyBytes())
- if err != nil {
- t.Fatalf("%v", err)
- }
-
- plainText := vector.PlainTextBytes()
- cipherText := make([]byte, len(plainText))
- tag := make([]byte, TagSize)
- Encrypt(cipher, cipherText, plainText, vector.NonceBytes(), tag)
-
- expectedCipherText := vector.CipherTextBytes()
- if !bytes.Equal(cipherText, expectedCipherText) {
- t.Fatalf("expected CipherText %#v, got %#v", expectedCipherText, cipherText)
- }
-
- expectedTag := vector.TagBytes()
- if !bytes.Equal(tag, expectedTag) {
- t.Fatalf("expected tag %#v, got %#v", expectedTag, tag)
- }
- }
-}
-
-func TestDecryptOCBAES128Vectors(t *testing.T) {
- for _, vector := range ocb128Vectors {
- cipher, err := aes.NewCipher(vector.KeyBytes())
- if err != nil {
- t.Fatalf("%v", err)
- }
-
- cipherText := vector.CipherTextBytes()
- plainText := make([]byte, len(cipherText))
- tag := make([]byte, TagSize)
- Decrypt(cipher, plainText, cipherText, vector.NonceBytes(), tag)
-
- expectedPlainText := vector.PlainTextBytes()
- if !bytes.Equal(plainText, expectedPlainText) {
- t.Fatalf("expected PlainText %#v, got %#v", expectedPlainText, plainText)
- }
-
- expectedTag := vector.TagBytes()
- if !bytes.Equal(tag, expectedTag) {
- t.Fatalf("expected tag %#v, got %#v", expectedTag, tag)
- }
- }
-} \ No newline at end of file
+// Copyright (c) 2010-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 ocb2
+
+import (
+ "bytes"
+ "crypto/aes"
+ "encoding/hex"
+ "testing"
+)
+
+func MustDecodeHex(s string) []byte {
+ buf, err := hex.DecodeString(s)
+ if err != nil {
+ panic("MustDecodeHex: " + err.Error())
+ }
+ return buf
+}
+
+type ocbVector struct {
+ Name string
+ Key string
+ Nonce string
+ Header string
+ PlainText string
+ CipherText string
+ Tag string
+}
+
+func (v ocbVector) KeyBytes() []byte {
+ return MustDecodeHex(v.Key)
+}
+
+func (v ocbVector) NonceBytes() []byte {
+ return MustDecodeHex(v.Nonce)
+}
+
+func (v ocbVector) PlainTextBytes() []byte {
+ return MustDecodeHex(v.PlainText)
+}
+
+func (v ocbVector) CipherTextBytes() []byte {
+ return MustDecodeHex(v.CipherText)
+}
+
+func (v ocbVector) TagBytes() []byte {
+ return MustDecodeHex(v.Tag)
+}
+
+// ocb128Vectors are the test vectors for OCB-AES128 from
+// http://www.cs.ucdavis.edu/~rogaway/papers/draft-krovetz-ocb-00.txt
+//
+// Note: currently, the vectors with headers are not included in this list
+// as this implementation does not implement header authentication.
+var ocb128Vectors = []ocbVector{
+ {
+ Name: "OCB2-AES-128-001",
+ Key: "000102030405060708090A0B0C0D0E0F",
+ Nonce: "000102030405060708090A0B0C0D0E0F",
+ PlainText: "",
+ CipherText: "",
+ Tag: "BF3108130773AD5EC70EC69E7875A7B0",
+ },
+ {
+ Name: "OCB2-AES-128-002",
+ Key: "000102030405060708090A0B0C0D0E0F",
+ Nonce: "000102030405060708090A0B0C0D0E0F",
+ PlainText: "0001020304050607",
+ CipherText: "C636B3A868F429BB",
+ Tag: "A45F5FDEA5C088D1D7C8BE37CABC8C5C",
+ },
+ {
+ Name: "OCB2-AES-128-003",
+ Key: "000102030405060708090A0B0C0D0E0F",
+ Nonce: "000102030405060708090A0B0C0D0E0F",
+ PlainText: "000102030405060708090A0B0C0D0E0F",
+ CipherText: "52E48F5D19FE2D9869F0C4A4B3D2BE57",
+ Tag: "F7EE49AE7AA5B5E6645DB6B3966136F9",
+ },
+ {
+ Name: "OCB2-AES-128-003",
+ Key: "000102030405060708090A0B0C0D0E0F",
+ Nonce: "000102030405060708090A0B0C0D0E0F",
+ PlainText: "000102030405060708090A0B0C0D0E0F1011121314151617",
+ CipherText: "F75D6BC8B4DC8D66B836A2B08B32A636CC579E145D323BEB",
+ Tag: "A1A50F822819D6E0A216784AC24AC84C",
+ },
+ {
+ Name: "OCB2-AES-128-004",
+ Key: "000102030405060708090A0B0C0D0E0F",
+ Nonce: "000102030405060708090A0B0C0D0E0F",
+ PlainText: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+ CipherText: "F75D6BC8B4DC8D66B836A2B08B32A636CEC3C555037571709DA25E1BB0421A27",
+ Tag: "09CA6C73F0B5C6C5FD587122D75F2AA3",
+ },
+ {
+ Name: "OCB2-AES-128-005",
+ Key: "000102030405060708090A0B0C0D0E0F",
+ Nonce: "000102030405060708090A0B0C0D0E0F",
+ PlainText: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+ CipherText: "F75D6BC8B4DC8D66B836A2B08B32A6369F1CD3C5228D79FD6C267F5F6AA7B231C7DFB9D59951AE9C",
+ Tag: "9DB0CDF880F73E3E10D4EB3217766688",
+ },
+}
+
+func TestTimes2(t *testing.T) {
+ msg := [aes.BlockSize]byte{
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ }
+ expected := [aes.BlockSize]byte{
+ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b,
+ }
+
+ times2(msg[0:])
+ if !bytes.Equal(msg[0:], expected[0:]) {
+ t.Fatalf("times2 produces invalid output: %v, expected: %v", msg, expected)
+ }
+}
+
+func TestTimes3(t *testing.T) {
+ msg := [aes.BlockSize]byte{
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ }
+ expected := [aes.BlockSize]byte{
+ 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85,
+ }
+
+ times3(msg[0:])
+ if !bytes.Equal(msg[0:], expected[0:]) {
+ t.Errorf("times3 produces invalid output: %v, expected: %v", msg, expected)
+ }
+}
+
+func TestZeros(t *testing.T) {
+ var msg [aes.BlockSize]byte
+ zeros(msg[0:])
+ for i := 0; i < len(msg); i++ {
+ if msg[i] != 0 {
+ t.Fatalf("zeros does not zero slice.")
+ }
+ }
+}
+
+func TestXor(t *testing.T) {
+ msg := [aes.BlockSize]byte{
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ }
+ var out [aes.BlockSize]byte
+ xor(out[0:], msg[0:], msg[0:])
+ for i := 0; i < len(out); i++ {
+ if out[i] != 0 {
+ t.Fatalf("XOR broken")
+ }
+ }
+}
+
+func TestEncryptOCBAES128Vectors(t *testing.T) {
+ for _, vector := range ocb128Vectors {
+ cipher, err := aes.NewCipher(vector.KeyBytes())
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+
+ plainText := vector.PlainTextBytes()
+ cipherText := make([]byte, len(plainText))
+ tag := make([]byte, TagSize)
+ Encrypt(cipher, cipherText, plainText, vector.NonceBytes(), tag)
+
+ expectedCipherText := vector.CipherTextBytes()
+ if !bytes.Equal(cipherText, expectedCipherText) {
+ t.Fatalf("expected CipherText %#v, got %#v", expectedCipherText, cipherText)
+ }
+
+ expectedTag := vector.TagBytes()
+ if !bytes.Equal(tag, expectedTag) {
+ t.Fatalf("expected tag %#v, got %#v", expectedTag, tag)
+ }
+ }
+}
+
+func TestDecryptOCBAES128Vectors(t *testing.T) {
+ for _, vector := range ocb128Vectors {
+ cipher, err := aes.NewCipher(vector.KeyBytes())
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+
+ cipherText := vector.CipherTextBytes()
+ plainText := make([]byte, len(cipherText))
+ if Decrypt(cipher, plainText, cipherText, vector.NonceBytes(), vector.TagBytes()) == false {
+ t.Fatalf("expected decrypt success; got failure. tag mismatch?")
+ }
+
+ expectedPlainText := vector.PlainTextBytes()
+ if !bytes.Equal(plainText, expectedPlainText) {
+ t.Fatalf("expected PlainText %#v, got %#v", expectedPlainText, plainText)
+ }
+ }
+}