X-Git-Url: http://www.git.cypherpunks.ru/?p=gogost.git;a=blobdiff_plain;f=gost28147%2Fwrap.go;fp=gost28147%2Fwrap.go;h=24190ea97d79919bc672d0cf93e50a09b499b79e;hp=0000000000000000000000000000000000000000;hb=1b5570c74dc84b97653e267f3cb0f938b5bf4b80;hpb=81d5e6635251272cdb1ea4b0bf5b9793a0e12a4d diff --git a/gost28147/wrap.go b/gost28147/wrap.go new file mode 100644 index 0000000..24190ea --- /dev/null +++ b/gost28147/wrap.go @@ -0,0 +1,83 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2023 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 +// the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost28147 + +import ( + "bytes" + "crypto/subtle" + "encoding/binary" +) + +func WrapGost(ukm, kek, cek []byte) []byte { + c := NewCipher(kek, &SboxIdGost2814789CryptoProAParamSet) + mac, err := c.NewMAC(4, ukm) + if err != nil { + panic(err) + } + _, err = mac.Write(cek) + if err != nil { + panic(err) + } + cekMac := mac.Sum(nil) + cekEnc := make([]byte, 32) + c.NewECBEncrypter().CryptBlocks(cekEnc, cek) + return bytes.Join([][]byte{ukm, cekEnc, cekMac}, nil) +} + +func UnwrapGost(kek, data []byte) []byte { + ukm, data := data[:8], data[8:] + cekEnc, cekMac := data[:KeySize], data[KeySize:] + c := NewCipher(kek, &SboxIdGost2814789CryptoProAParamSet) + cek := make([]byte, 32) + c.NewECBDecrypter().CryptBlocks(cek, cekEnc) + mac, err := c.NewMAC(4, ukm) + if err != nil { + panic(err) + } + _, err = mac.Write(cek) + if err != nil { + panic(err) + } + if subtle.ConstantTimeCompare(mac.Sum(nil), cekMac) != 1 { + return nil + } + return cek +} + +func DiversifyCryptoPro(kek, ukm []byte) []byte { + out := kek + for i := 0; i < 8; i++ { + var s1, s2 uint64 + for j := 0; j < 8; j++ { + k := binary.LittleEndian.Uint32(out[j*4 : j*4+4]) + if (ukm[i]>>j)&1 > 0 { + s1 += uint64(k) + } else { + s2 += uint64(k) + } + } + iv := make([]byte, 8) + binary.LittleEndian.PutUint32(iv[:4], uint32(s1%(1<<32))) + binary.LittleEndian.PutUint32(iv[4:], uint32(s2%(1<<32))) + c := NewCipher(out, &SboxIdGost2814789CryptoProAParamSet) + c.NewCFBEncrypter(iv).XORKeyStream(out, out) + } + return out +} + +func UnwrapCryptoPro(kek, data []byte) []byte { + return UnwrapGost(DiversifyCryptoPro(kek, data[:8]), data) +}