X-Git-Url: http://www.git.cypherpunks.ru/?p=gogost.git;a=blobdiff_plain;f=mgm%2Fmode.go;h=38b9ab349cc6bc290e8a8b3367a8890ca00fba17;hp=fdbfa4277fad5577b2fc1af15a2857e547a4099c;hb=7e8907d3f9c6eeec0a49e563923cb0aab0e9aeac;hpb=c07494bbd559b9d00f391e28cfd070e18afe9900 diff --git a/mgm/mode.go b/mgm/mode.go index fdbfa42..38b9ab3 100644 --- a/mgm/mode.go +++ b/mgm/mode.go @@ -1,5 +1,5 @@ // GoGOST -- Pure Go GOST cryptographic functions library -// Copyright (C) 2015-2019 Sergey Matveev +// Copyright (C) 2015-2021 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -21,82 +21,58 @@ import ( "crypto/hmac" "encoding/binary" "errors" - "math/big" ) -var ( - R64 *big.Int = big.NewInt(0) - R128 *big.Int = big.NewInt(0) -) - -func init() { - R64.SetBytes([]byte{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, - }) - R128.SetBytes([]byte{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, - }) +type Mul interface { + Mul(x, y []byte) []byte } type MGM struct { - maxSize uint64 + MaxSize uint64 + BlockSize int + TagSize int cipher cipher.Block - blockSize int - tagSize int icn []byte bufP []byte bufC []byte padded []byte sum []byte - - x *big.Int - y *big.Int - z *big.Int - maxBit int - r *big.Int - mulBuf []byte + mul Mul } func NewMGM(cipher cipher.Block, tagSize int) (cipher.AEAD, error) { blockSize := cipher.BlockSize() if !(blockSize == 8 || blockSize == 16) { - return nil, errors.New("MGM supports only 64/128 blocksizes") + return nil, errors.New("gogost/mgm: only 64/128 blocksizes allowed") } if tagSize < 4 || tagSize > blockSize { - return nil, errors.New("invalid tag size") + return nil, errors.New("gogost/mgm: invalid tag size") } mgm := MGM{ - maxSize: uint64(1< 0 { @@ -127,86 +103,86 @@ func (mgm *MGM) validateSizes(text, additionalData []byte) { if len(text) == 0 && len(additionalData) == 0 { panic("at least either *text or additionalData must be provided") } - if uint64(len(additionalData)) > mgm.maxSize { + if uint64(len(additionalData)) > mgm.MaxSize { panic("additionalData is too big") } - if uint64(len(text)+len(additionalData)) > mgm.maxSize { + if uint64(len(text)+len(additionalData)) > mgm.MaxSize { panic("*text with additionalData are too big") } } func (mgm *MGM) auth(out, text, ad []byte) { - for i := 0; i < mgm.blockSize; i++ { + for i := 0; i < mgm.BlockSize; i++ { mgm.sum[i] = 0 } adLen := len(ad) * 8 textLen := len(text) * 8 mgm.icn[0] |= 0x80 mgm.cipher.Encrypt(mgm.bufP, mgm.icn) // Z_1 = E_K(1 || ICN) - for len(ad) >= mgm.blockSize { + for len(ad) >= mgm.BlockSize { mgm.cipher.Encrypt(mgm.bufC, mgm.bufP) // H_i = E_K(Z_i) xor( // sum (xor)= H_i (x) A_i mgm.sum, mgm.sum, - mgm.mul(mgm.bufC, ad[:mgm.blockSize]), + mgm.mul.Mul(mgm.bufC, ad[:mgm.BlockSize]), ) - incr(mgm.bufP[:mgm.blockSize/2]) // Z_{i+1} = incr_l(Z_i) - ad = ad[mgm.blockSize:] + incr(mgm.bufP[:mgm.BlockSize/2]) // Z_{i+1} = incr_l(Z_i) + ad = ad[mgm.BlockSize:] } if len(ad) > 0 { copy(mgm.padded, ad) - for i := len(ad); i < mgm.blockSize; i++ { + for i := len(ad); i < mgm.BlockSize; i++ { mgm.padded[i] = 0 } mgm.cipher.Encrypt(mgm.bufC, mgm.bufP) - xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufC, mgm.padded)) - incr(mgm.bufP[:mgm.blockSize/2]) + xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.padded)) + incr(mgm.bufP[:mgm.BlockSize/2]) } - for len(text) >= mgm.blockSize { + for len(text) >= mgm.BlockSize { mgm.cipher.Encrypt(mgm.bufC, mgm.bufP) // H_{h+j} = E_K(Z_{h+j}) xor( // sum (xor)= H_{h+j} (x) C_j mgm.sum, mgm.sum, - mgm.mul(mgm.bufC, text[:mgm.blockSize]), + mgm.mul.Mul(mgm.bufC, text[:mgm.BlockSize]), ) - incr(mgm.bufP[:mgm.blockSize/2]) // Z_{h+j+1} = incr_l(Z_{h+j}) - text = text[mgm.blockSize:] + incr(mgm.bufP[:mgm.BlockSize/2]) // Z_{h+j+1} = incr_l(Z_{h+j}) + text = text[mgm.BlockSize:] } if len(text) > 0 { copy(mgm.padded, text) - for i := len(text); i < mgm.blockSize; i++ { + for i := len(text); i < mgm.BlockSize; i++ { mgm.padded[i] = 0 } mgm.cipher.Encrypt(mgm.bufC, mgm.bufP) - xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufC, mgm.padded)) - incr(mgm.bufP[:mgm.blockSize/2]) + xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.padded)) + incr(mgm.bufP[:mgm.BlockSize/2]) } mgm.cipher.Encrypt(mgm.bufP, mgm.bufP) // H_{h+q+1} = E_K(Z_{h+q+1}) // len(A) || len(C) - if mgm.blockSize == 8 { + if mgm.BlockSize == 8 { binary.BigEndian.PutUint32(mgm.bufC, uint32(adLen)) - binary.BigEndian.PutUint32(mgm.bufC[mgm.blockSize/2:], uint32(textLen)) + binary.BigEndian.PutUint32(mgm.bufC[mgm.BlockSize/2:], uint32(textLen)) } else { binary.BigEndian.PutUint64(mgm.bufC, uint64(adLen)) - binary.BigEndian.PutUint64(mgm.bufC[mgm.blockSize/2:], uint64(textLen)) + binary.BigEndian.PutUint64(mgm.bufC[mgm.BlockSize/2:], uint64(textLen)) } // sum (xor)= H_{h+q+1} (x) (len(A) || len(C)) - xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufP, mgm.bufC)) + xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.bufP)) mgm.cipher.Encrypt(mgm.bufP, mgm.sum) // E_K(sum) - copy(out, mgm.bufP[:mgm.tagSize]) // MSB_S(E_K(sum)) + copy(out, mgm.bufP[:mgm.TagSize]) // MSB_S(E_K(sum)) } func (mgm *MGM) crypt(out, in []byte) { mgm.icn[0] &= 0x7F mgm.cipher.Encrypt(mgm.bufP, mgm.icn) // Y_1 = E_K(0 || ICN) - for len(in) >= mgm.blockSize { + for len(in) >= mgm.BlockSize { mgm.cipher.Encrypt(mgm.bufC, mgm.bufP) // E_K(Y_i) xor(out, mgm.bufC, in) // C_i = P_i (xor) E_K(Y_i) - incr(mgm.bufP[mgm.blockSize/2:]) // Y_i = incr_r(Y_{i-1}) - out = out[mgm.blockSize:] - in = in[mgm.blockSize:] + incr(mgm.bufP[mgm.BlockSize/2:]) // Y_i = incr_r(Y_{i-1}) + out = out[mgm.BlockSize:] + in = in[mgm.BlockSize:] } if len(in) > 0 { mgm.cipher.Encrypt(mgm.bufC, mgm.bufP) @@ -217,14 +193,14 @@ func (mgm *MGM) crypt(out, in []byte) { func (mgm *MGM) Seal(dst, nonce, plaintext, additionalData []byte) []byte { mgm.validateNonce(nonce) mgm.validateSizes(plaintext, additionalData) - if uint64(len(plaintext)) > mgm.maxSize { + if uint64(len(plaintext)) > mgm.MaxSize { panic("plaintext is too big") } - ret, out := sliceForAppend(dst, len(plaintext)+mgm.tagSize) + ret, out := sliceForAppend(dst, len(plaintext)+mgm.TagSize) copy(mgm.icn, nonce) mgm.crypt(out, plaintext) mgm.auth( - out[len(plaintext):len(plaintext)+mgm.tagSize], + out[len(plaintext):len(plaintext)+mgm.TagSize], out[:len(plaintext)], additionalData, ) @@ -234,15 +210,18 @@ func (mgm *MGM) Seal(dst, nonce, plaintext, additionalData []byte) []byte { func (mgm *MGM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { mgm.validateNonce(nonce) mgm.validateSizes(ciphertext, additionalData) - if uint64(len(ciphertext)-mgm.tagSize) > mgm.maxSize { + if len(ciphertext) < mgm.TagSize { + return nil, errors.New("ciphertext is too short") + } + if uint64(len(ciphertext)-mgm.TagSize) > mgm.MaxSize { panic("ciphertext is too big") } - ret, out := sliceForAppend(dst, len(ciphertext)-mgm.tagSize) - ct := ciphertext[:len(ciphertext)-mgm.tagSize] + ret, out := sliceForAppend(dst, len(ciphertext)-mgm.TagSize) + ct := ciphertext[:len(ciphertext)-mgm.TagSize] copy(mgm.icn, nonce) mgm.auth(mgm.sum, ct, additionalData) - if !hmac.Equal(mgm.sum[:mgm.tagSize], ciphertext[len(ciphertext)-mgm.tagSize:]) { - return nil, errors.New("invalid authentication tag") + if !hmac.Equal(mgm.sum[:mgm.TagSize], ciphertext[len(ciphertext)-mgm.TagSize:]) { + return nil, errors.New("gogost/mgm: invalid authentication tag") } mgm.crypt(out, ct) return ret, nil