// CCM Mode, defined in// NIST Special Publication SP 800-38C.package ccmimport ()type ccm struct { c cipher.Block mac *mac nonceSize int tagSize int}// NewCCMWithNonceAndTagSizes returns the given 128-bit, block cipher wrapped in Counter with CBC-MAC Mode, which accepts nonces of the given length.// the formatting of this function is defined in SP800-38C, Appendix A.// Each arguments have own valid range:// nonceSize should be one of the {7, 8, 9, 10, 11, 12, 13}.// tagSize should be one of the {4, 6, 8, 10, 12, 14, 16}.// Otherwise, it panics.// The maximum payload size is defined as 1<<uint((15-nonceSize)*8)-1.// If the given payload size exceeds the limit, it returns a error (Seal returns nil instead).// The payload size is defined as len(plaintext) on Seal, len(ciphertext)-tagSize on Open.func ( cipher.Block, , int) (cipher.AEAD, error) {if .BlockSize() != 16 {returnnil, errors.New("cipher: CCM mode requires 128-bit block cipher") }if !(7 <= && <= 13) {returnnil, errors.New("cipher: invalid nonce size") }if !(4 <= && <= 16 && &1 == 0) {returnnil, errors.New("cipher: invalid tag size") }return &ccm{c: ,mac: newMAC(),nonceSize: ,tagSize: , }, nil}func ( *ccm) () int {return .nonceSize}func ( *ccm) () int {return .tagSize}func ( *ccm) (, , , []byte) []byte {iflen() != .nonceSize {panic("cipher: incorrect nonce length given to CCM") }// AEAD interface doesn't provide a way to return errors. // So it returns nil instead.ifmaxUvarint(15-.nonceSize) < uint64(len()) {returnnil } , := sliceForAppend(, len()+.mac.Size())// Formatting of the Counter Blocks are defined in A.3. := make([]byte, 16) // Ctr0 [0] = byte(15 - .nonceSize - 1) // [q-1]3copy([1:], ) // N := [len():] // S0 .c.Encrypt(, ) [15] = 1// Ctr1 := cipher.NewCTR(.c, ) .XORKeyStream(, ) := .getTag(, , )xorBytes(, , ) // T^S0return [:len()+.tagSize]}func ( *ccm) (, , , []byte) ([]byte, error) {iflen() != .nonceSize {panic("cipher: incorrect nonce length given to CCM") }iflen() <= .tagSize {panic("cipher: incorrect ciphertext length given to CCM") }ifmaxUvarint(15-.nonceSize) < uint64(len()-.tagSize) {returnnil, errors.New("cipher: len(ciphertext)-tagSize exceeds the maximum payload size") } , := sliceForAppend(, len()-.tagSize)// Formatting of the Counter Blocks are defined in A.3. := make([]byte, 16) // Ctr0 [0] = byte(15 - .nonceSize - 1) // [q-1]3copy([1:], ) // N := make([]byte, 16) // S0 .c.Encrypt(, ) [15] = 1// Ctr1 := cipher.NewCTR(.c, ) .XORKeyStream(, [:len()]) := .getTag(, , )xorBytes(, , )if !bytes.Equal([:.tagSize], [len():]) {returnnil, errors.New("crypto/ccm: message authentication failed") }return , nil}// getTag reuses a Ctr block for making the B0 block because of some parts are the same.// For more details, see A.2 and A.3.func ( *ccm) (, , []byte) []byte { .mac.Reset() := // B0 [0] |= byte(((.tagSize - 2) / 2) << 3) // [(t-2)/2]3putUvarint([1+.nonceSize:], uint64(len())) // Qiflen() > 0 { [0] |= 1 << 6// Adata .mac.Write()iflen() < (1<<15 - 1<<7) {putUvarint([:2], uint64(len())) .mac.Write([:2]) } elseiflen() <= 1<<31-1 { [0] = 0xff [1] = 0xfeputUvarint([2:6], uint64(len())) .mac.Write([:6]) } else { [0] = 0xff [1] = 0xffputUvarint([2:10], uint64(len())) .mac.Write([:10]) } .mac.Write() .mac.PadZero() } else { .mac.Write() } .mac.Write() .mac.PadZero()return .mac.Sum(nil)}func maxUvarint( int) uint64 {return1<<uint(*8) - 1}// put uint64 as big endian.func putUvarint( []byte, uint64) {for := 0; < len(); ++ { [] = byte( >> uint(8*(len()-1-))) }}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.