]> Cypherpunks.ru repositories - gogost.git/blobdiff - mgm/mode.go
Raise copyright years in advance
[gogost.git] / mgm / mode.go
index c281567fbaf9ceb8dc33777314e2122788064a7b..cbba435f4755fdeb862b4f1ab82224a482a9e063 100644 (file)
@@ -1,5 +1,5 @@
 // GoGOST -- Pure Go GOST cryptographic functions library
-// Copyright (C) 2015-2021 Sergey Matveev <stargrave@stargrave.org>
+// Copyright (C) 2015-2024 Sergey Matveev <stargrave@stargrave.org>
 //
 // 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,22 +21,13 @@ import (
        "crypto/hmac"
        "encoding/binary"
        "errors"
-       "math/big"
+       "fmt"
 )
 
-var (
-       R64  *big.Int = big.NewInt(0)
-       R128 *big.Int = big.NewInt(0)
-)
+var InvalidTag = errors.New("gogost/mgm: invalid authentication tag")
 
-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 {
@@ -49,22 +40,16 @@ type MGM struct {
        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("gogost/mgm: only 64/128 blocksizes allowed")
+               return nil, errors.New("gogost/mgm: only {64|128} blocksizes allowed")
        }
        if tagSize < 4 || tagSize > blockSize {
-               return nil, errors.New("gogost/mgm: invalid tag size")
+               return nil, fmt.Errorf("gogost/mgm: invalid tag size (4<=%d<=%d)", tagSize, blockSize)
        }
        mgm := MGM{
                MaxSize:   uint64(1<<uint(blockSize*8/2) - 1),
@@ -76,17 +61,11 @@ func NewMGM(cipher cipher.Block, tagSize int) (cipher.AEAD, error) {
                bufC:      make([]byte, blockSize),
                padded:    make([]byte, blockSize),
                sum:       make([]byte, blockSize),
-               x:         big.NewInt(0),
-               y:         big.NewInt(0),
-               z:         big.NewInt(0),
-               mulBuf:    make([]byte, blockSize),
        }
        if blockSize == 8 {
-               mgm.maxBit = 64 - 1
-               mgm.r = R64
+               mgm.mul = newMul64()
        } else {
-               mgm.maxBit = 128 - 1
-               mgm.r = R128
+               mgm.mul = newMul128()
        }
        return &mgm, nil
 }
@@ -148,7 +127,7 @@ func (mgm *MGM) auth(out, text, ad []byte) {
                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:]
@@ -159,7 +138,7 @@ func (mgm *MGM) auth(out, text, ad []byte) {
                        mgm.padded[i] = 0
                }
                mgm.cipher.Encrypt(mgm.bufC, mgm.bufP)
-               xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufC, mgm.padded))
+               xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.padded))
                incr(mgm.bufP[:mgm.BlockSize/2])
        }
 
@@ -168,7 +147,7 @@ func (mgm *MGM) auth(out, text, ad []byte) {
                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:]
@@ -179,7 +158,7 @@ func (mgm *MGM) auth(out, text, ad []byte) {
                        mgm.padded[i] = 0
                }
                mgm.cipher.Encrypt(mgm.bufC, mgm.bufP)
-               xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufC, mgm.padded))
+               xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.padded))
                incr(mgm.bufP[:mgm.BlockSize/2])
        }
 
@@ -193,7 +172,7 @@ func (mgm *MGM) auth(out, text, ad []byte) {
                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))
 }
@@ -231,11 +210,13 @@ func (mgm *MGM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
        return ret
 }
 
+// Open the authenticated ciphertext. If authentication tag is invalid,
+// then InvalidTag error is returned.
 func (mgm *MGM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
        mgm.validateNonce(nonce)
        mgm.validateSizes(ciphertext, additionalData)
        if len(ciphertext) < mgm.TagSize {
-               return nil, errors.New("ciphertext is too short")
+               return nil, fmt.Errorf("ciphertext is too short (%d<%d)", len(ciphertext), mgm.TagSize)
        }
        if uint64(len(ciphertext)-mgm.TagSize) > mgm.MaxSize {
                panic("ciphertext is too big")
@@ -245,7 +226,7 @@ func (mgm *MGM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, err
        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("gogost/mgm: invalid authentication tag")
+               return nil, InvalidTag
        }
        mgm.crypt(out, ct)
        return ret, nil