├── .gitmodules ├── AUTHORS ├── BSDmakefile ├── COPYING ├── COPYING.LESSER ├── GNUmakefile ├── INSTALL ├── NEWS ├── PUBKEY.asc ├── README ├── THANKS ├── TODO ├── VERSION ├── cmd ├── streebog256 │ └── main.go └── streebog512 │ └── main.go ├── common.mk ├── gogost.go ├── gost28147 ├── cbc_test.go ├── cfb.go ├── cfb_test.go ├── cipher.go ├── cipher_test.go ├── ctr.go ├── ctr_test.go ├── ecb.go ├── ecb_test.go ├── mac.go ├── mac_test.go └── sbox.go ├── gost3410 ├── 2001_test.go ├── 2012_test.go ├── curve.go ├── doc.go ├── params.go ├── private.go ├── public.go ├── ukm.go ├── utils.go ├── vko.go ├── vko2001.go ├── vko2001_test.go ├── vko2012.go └── vko2012_test.go ├── gost34112012256 └── hash.go ├── gost34112012512 └── hash.go ├── gost341194 ├── hash.go ├── hash_test.go └── pbkdf2_test.go ├── gost3412 ├── cipher.go └── cipher_test.go ├── gost3413 └── padding.go ├── internal └── gost34112012 │ ├── hash.go │ ├── hash_test.go │ └── hmac_test.go ├── makedist.sh ├── www.mk └── www.texi /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/golang.org/x/crypto"] 2 | path = src/golang.org/x/crypto 3 | url = https://go.googlesource.com/crypto 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | * Sergey Matveev 2 | -------------------------------------------------------------------------------- /BSDmakefile: -------------------------------------------------------------------------------- 1 | GOPATH != pwd 2 | VERSION != cat VERSION 3 | 4 | include common.mk 5 | -------------------------------------------------------------------------------- /COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | GOPATH = $(shell pwd) 2 | VERSION = $(shell cat VERSION) 3 | 4 | include common.mk 5 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Preferable way is to download tarball with the signature from official 2 | website and, for example, run tests with benchmarks: 3 | 4 | % wget http://gogost.cypherpunks.ru/gogost-1.1.tar.xz 5 | % wget http://gogost.cypherpunks.ru/gogost-1.1.tar.xz.sig 6 | % gpg --verify gogost-1.1.tar.xz.sig gogost-1.1.tar.xz 7 | % xz -d < gogost-1.1.tar.xz | tar xf - 8 | % make -C gogost-1.1 all bench 9 | % echo hello world | ./gogost-1.1/streebog256 10 | f72018189a5cfb803dbe1f2149cf554c40093d8e7f81c21e08ac5bcd09d9934d 11 | 12 | And then you can include its source code in your project for example 13 | like this: 14 | 15 | % mkdir -p myproj/src 16 | % export GOPATH=$PWD/myproj 17 | % cd myproj/src 18 | % cat > main.go < 49 | 50 | Look in PUBKEY.asc file. 51 | % gpg --keyserver hkp://keys.gnupg.net/ --recv-keys 0x82343436696FC85A 52 | % gpg --auto-key-locate dane --locate-keys gogost at cypherpunks dot ru 53 | % gpg --auto-key-locate wkd --locate-keys gogost at cypherpunks dot ru 54 | % gpg --auto-key-locate pka --locate-keys gogost at cypherpunks dot ru 55 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2.1: 2 | Licence changed from GNU GPLv3+ to GNU LGPLv3+. 3 | 4 | 2.0: 5 | * 34.11-2012 is split on two different modules: gost34112012256 and 6 | gost34112012512 7 | * 34.11-94's digest is reversed. Now it is compatible with TC26's 8 | HMAC and PBKDF2 test vectors 9 | * gogost-streebog is split to streebog256 and streebog512 10 | correspondingly by analogy with sha* utilities 11 | * added VKO 34.10-2012 support with corresponding test vectors 12 | * gost3410.DigestSizeX is renamed to gost3410.ModeX because it is 13 | not related to digest size, but parameters and key sizes 14 | * KEK functions take big.Int UKM value. Use NewUKM to unmarshal 15 | raw binary UKM 16 | 17 | 1.1: 18 | * gogost-streebog is able to use either 256 or 512 bits digest size 19 | * 34.13-2015 padding methods 20 | * 28147-89 CBC mode of operation 21 | 22 | 1.0: 23 | Initial release. 24 | -------------------------------------------------------------------------------- /PUBKEY.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mQENBFfXoXsBCADKKxVI2GjDU5f3L2Y2m9oz089viCwVkD0plf3Bo8yaAnyxp/an 4 | EjTYQnfE2QQxbixKz2A+z/mfrFrJld3zM/rmu0WJxmEBb7J59j8uKa8DblxJuYJh 5 | rWWhwzm8FSC2bITzF0dFSSXSF9xcM8CoRJOBeOzpVNPopKxXW94MgHw/xlXvjASn 6 | cbLDKM2eFYXnWMRZsnrfVs87r8OoHxzDCWZ16/CjB5qspn5Yf7c/sXE2C5EIMJce 7 | biiXcLTPxKG5B5Tncmsh9HA0CquGciftm34bJxTJSPkw/0B3ROyY7yadlud7XjLI 8 | Ak2AP3y0AHgI4q4Q9YzPeotryG91hj6lii8jABEBAAG0J0dvR09TVCByZWxlYXNl 9 | cyA8Z29nb3N0QGN5cGhlcnB1bmtzLnJ1PokBQAQTAQgAKgUCV9ehewIbAwwLCgkN 10 | CAwHCwMEAQIHFQoJCAsDAgUWAgEDAAIeAQIXgAAKCRCCNDQ2aW/IWibQCADF59c2 11 | aKHVEqqm6tnyu0CFKuVWAikoss3DB8A3Vp1kLxOOoXcnSDMM1v+C6oGU7TDcobZ9 12 | zH2XZpnfj9MEZ5jypb2z+QlkPN7cJBOGvSJ8XpTt8E8/heyD40KS61VBNXgN3BZL 13 | owKBcppwthSVRntjexHzn7ha4HE8j8ysypMBtsw7x+3iKZD4roHrYdp4ddOoZT1s 14 | xLsNmmbUzln2ieCD/mMb8taVpFJhuAWH2o6HJTh31b/+T0AN3QL999AQcR93jF2U 15 | o6/MJ0m3TzXHvUTnIOXCU7xlG464+6+rRACBbRlO3wa0WSdSeQSFIy1ienYxj63W 16 | iXmU5IA05VS613JaiF4EEBEIAAYFAlfXoZcACgkQrhqBCeSYV+/Y1AD9Eg0+OMLb 17 | 8ygnl+v8XUQqsf7fCcELW3oadFMu0RhcDNQA/20GNbS0omsycQkqmxYMQLkWa5wx 18 | 4kzapQYmseDye0zy 19 | =sx2q 20 | -----END PGP PUBLIC KEY BLOCK----- 21 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Pure Go GOST cryptographic functions library. 2 | 3 | GOST is GOvernment STandard of Russian Federation (and Soviet Union). 4 | 5 | * GOST 28147-89 (RFC 5830) block cipher with ECB, CNT (CTR), CFB, MAC 6 | CBC (RFC 4357) modes of operation 7 | * various 28147-89-related S-boxes included 8 | * GOST R 34.11-94 hash function (RFC 5831) 9 | * GOST R 34.11-2012 Стрибог (Streebog) hash function (RFC 6986) 10 | * GOST R 34.10-2001 (RFC 5832) public key signature function 11 | * GOST R 34.10-2012 (RFC 7091) public key signature function 12 | * various 34.10 curve parameters included 13 | * VKO GOST R 34.10-2001 key agreement function (RFC 4357) 14 | * VKO GOST R 34.10-2012 key agreement function (RFC 7836) 15 | * GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (RFC 7801) 16 | * GOST R 34.13-2015 padding methods 17 | 18 | Known problems: 19 | 20 | * intermediate calculation values are not zeroed 21 | * 34.10 is not time constant and slow 22 | 23 | GoGOST is free software: see the file COPYING.LESSER for copying conditions. 24 | 25 | GoGOST'es home page is: http://gogost.cypherpunks.ru/ 26 | Also available as I2P service: 27 | http://a5zmymxbjreuvbftgzmu64vcw2ssa3s44c2dn2jryxee6utn34qa.b32.i2p/ 28 | You can read about GOST algorithms more: http://gost.cypherpunks.ru/ 29 | 30 | Please send questions, bug reports and patches to 31 | https://lists.cypherpunks.ru/mailman/listinfo/gost 32 | mailing list. Announcements also go to this mailing list. 33 | 34 | Development Git source code repository currently is located here: 35 | https://git.cypherpunks.ru/cgit.cgi/gogost.git/ 36 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | There are people deserving to be thanked for helping this project: 2 | 3 | * Dmitry Eremin-Solenikov for his 4 | suggestions of TK26 standards usage as a base point for serialized 5 | structures representation 6 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * 28147-89 and CryptoPro key wrapping (RFC 4357) 2 | * 28147-89 CryptoPro key meshing for CFB mode (RFC 4357) 3 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.1 2 | -------------------------------------------------------------------------------- /cmd/streebog256/main.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // Command-line 34.11-2012 256-bit hash function. 19 | package main 20 | 21 | import ( 22 | "encoding/hex" 23 | "flag" 24 | "fmt" 25 | "io" 26 | "os" 27 | 28 | "github.com/martinlindhe/gogost" 29 | "github.com/martinlindhe/gogost/gost34112012256" 30 | ) 31 | 32 | var ( 33 | version = flag.Bool("version", false, "Print version information") 34 | ) 35 | 36 | func main() { 37 | flag.Parse() 38 | if *version { 39 | fmt.Println(gogost.Version) 40 | return 41 | } 42 | h := gost34112012256.New() 43 | io.Copy(h, os.Stdin) 44 | fmt.Println(hex.EncodeToString(h.Sum(nil))) 45 | } 46 | -------------------------------------------------------------------------------- /cmd/streebog512/main.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // Command-line 34.11-2012 512-bit hash function. 19 | package main 20 | 21 | import ( 22 | "encoding/hex" 23 | "flag" 24 | "fmt" 25 | "io" 26 | "os" 27 | 28 | "github.com/martinlindhe/gogost" 29 | "github.com/martinlindhe/gogost/gost34112012512" 30 | ) 31 | 32 | var ( 33 | version = flag.Bool("version", false, "Print version information") 34 | ) 35 | 36 | func main() { 37 | flag.Parse() 38 | if *version { 39 | fmt.Println(gogost.Version) 40 | return 41 | } 42 | h := gost34112012512.New() 43 | io.Copy(h, os.Stdin) 44 | fmt.Println(hex.EncodeToString(h.Sum(nil))) 45 | } 46 | -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | LDFLAGS = -X cypherpunks.ru/gogost.Version=$(VERSION) 2 | 3 | all: streebog256 streebog512 4 | 5 | streebog256: 6 | GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/gogost/cmd/streebog256 7 | 8 | streebog512: 9 | GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/gogost/cmd/streebog512 10 | 11 | bench: 12 | GOPATH=$(GOPATH) go test -benchmem -bench . cypherpunks.ru/gogost/... 13 | -------------------------------------------------------------------------------- /gogost.go: -------------------------------------------------------------------------------- 1 | // Pure Go GOST cryptographic functions library. 2 | package gogost 3 | 4 | var ( 5 | Version string 6 | ) 7 | -------------------------------------------------------------------------------- /gost28147/cbc_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "bytes" 22 | "crypto/cipher" 23 | "crypto/rand" 24 | "testing" 25 | "testing/quick" 26 | ) 27 | 28 | func TestCBCCrypter(t *testing.T) { 29 | var key [KeySize]byte 30 | var iv [BlockSize]byte 31 | rand.Read(key[:]) 32 | rand.Read(iv[:]) 33 | c := NewCipher(key, SboxDefault) 34 | f := func(pt []byte) bool { 35 | for i := 0; i < BlockSize; i++ { 36 | pt = append(pt, pt...) 37 | } 38 | ct := make([]byte, len(pt)) 39 | e := cipher.NewCBCEncrypter(c, iv[:]) 40 | e.CryptBlocks(ct, pt) 41 | d := cipher.NewCBCDecrypter(c, iv[:]) 42 | d.CryptBlocks(ct, ct) 43 | return bytes.Compare(pt, ct) == 0 44 | } 45 | if err := quick.Check(f, nil); err != nil { 46 | t.Error(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /gost28147/cfb.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | type CFBEncrypter struct { 21 | c *Cipher 22 | iv []byte 23 | } 24 | 25 | func (c *Cipher) NewCFBEncrypter(iv [BlockSize]byte) *CFBEncrypter { 26 | return &CFBEncrypter{c, iv[:]} 27 | } 28 | 29 | func (c *CFBEncrypter) XORKeyStream(dst, src []byte) { 30 | var n int 31 | i := 0 32 | MainLoop: 33 | for { 34 | c.c.Encrypt(c.iv, c.iv) 35 | for n = 0; n < BlockSize; n++ { 36 | if i*BlockSize+n == len(src) { 37 | break MainLoop 38 | } 39 | c.iv[n] ^= src[i*BlockSize+n] 40 | dst[i*BlockSize+n] = c.iv[n] 41 | } 42 | i++ 43 | } 44 | return 45 | } 46 | 47 | type CFBDecrypter struct { 48 | c *Cipher 49 | iv []byte 50 | } 51 | 52 | func (c *Cipher) NewCFBDecrypter(iv [BlockSize]byte) *CFBDecrypter { 53 | return &CFBDecrypter{c, iv[:]} 54 | } 55 | 56 | func (c *CFBDecrypter) XORKeyStream(dst, src []byte) { 57 | var n int 58 | i := 0 59 | MainLoop: 60 | for { 61 | c.c.Encrypt(c.iv, c.iv) 62 | for n = 0; n < BlockSize; n++ { 63 | if i*BlockSize+n == len(src) { 64 | break MainLoop 65 | } 66 | dst[i*BlockSize+n] = c.iv[n] ^ src[i*BlockSize+n] 67 | c.iv[n] = src[i*BlockSize+n] 68 | } 69 | i++ 70 | } 71 | return 72 | } 73 | -------------------------------------------------------------------------------- /gost28147/cfb_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "bytes" 22 | "crypto/cipher" 23 | "crypto/rand" 24 | "testing" 25 | "testing/quick" 26 | ) 27 | 28 | func TestCFBCryptomanager(t *testing.T) { 29 | key := [KeySize]byte{ 30 | 0x75, 0x71, 0x31, 0x34, 0xB6, 0x0F, 0xEC, 0x45, 31 | 0xA6, 0x07, 0xBB, 0x83, 0xAA, 0x37, 0x46, 0xAF, 32 | 0x4F, 0xF9, 0x9D, 0xA6, 0xD1, 0xB5, 0x3B, 0x5B, 33 | 0x1B, 0x40, 0x2A, 0x1B, 0xAA, 0x03, 0x0D, 0x1B, 34 | } 35 | sbox := &GostR3411_94_TestParamSet 36 | pt := []byte{ 37 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 38 | 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0x80, 0x00, 0x00, 39 | } 40 | ct := []byte{ 41 | 0x6E, 0xE8, 0x45, 0x86, 0xDD, 0x2B, 0xCA, 0x0C, 42 | 0xAD, 0x36, 0x16, 0x94, 0x0E, 0x16, 0x42, 0x42, 43 | } 44 | c := NewCipher(key, sbox) 45 | iv := [8]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} 46 | tmp := make([]byte, 16) 47 | fe := c.NewCFBEncrypter(iv) 48 | fe.XORKeyStream(tmp, pt) 49 | if bytes.Compare(tmp, ct) != 0 { 50 | t.Fail() 51 | } 52 | fd := c.NewCFBDecrypter(iv) 53 | fd.XORKeyStream(tmp, ct) 54 | if bytes.Compare(tmp, pt) != 0 { 55 | t.Fail() 56 | } 57 | } 58 | 59 | func TestCFBRandom(t *testing.T) { 60 | var key [KeySize]byte 61 | rand.Read(key[:]) 62 | c := NewCipher(key, SboxDefault) 63 | f := func(ivRaw []byte, pt []byte) bool { 64 | if len(pt) == 0 || len(ivRaw) < 8 { 65 | return true 66 | } 67 | var iv [8]byte 68 | copy(iv[:], ivRaw[:8]) 69 | ct := make([]byte, len(pt)) 70 | fe := c.NewCFBEncrypter(iv) 71 | fe.XORKeyStream(ct, pt) 72 | fd := c.NewCFBDecrypter(iv) 73 | pt2 := make([]byte, len(ct)) 74 | fd.XORKeyStream(pt2, ct) 75 | return bytes.Compare(pt2, pt) == 0 76 | } 77 | if err := quick.Check(f, nil); err != nil { 78 | t.Error(err) 79 | } 80 | } 81 | 82 | func TestCFBInterface(t *testing.T) { 83 | var key [32]byte 84 | var iv [8]byte 85 | c := NewCipher(key, SboxDefault) 86 | var _ cipher.Stream = c.NewCFBEncrypter(iv) 87 | var _ cipher.Stream = c.NewCFBDecrypter(iv) 88 | } 89 | -------------------------------------------------------------------------------- /gost28147/cipher.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST 28147-89 block cipher with ECB, CFB, CTR, MAC modes of operation. 19 | // RFC 5830. 20 | package gost28147 21 | 22 | const ( 23 | BlockSize = 8 24 | KeySize = 32 25 | ) 26 | 27 | // All 28147 operations are going with two 32-bit halves of the whole 28 | // block. nv is representation of that one half. 29 | type nv uint32 30 | 31 | // Cyclic 11-bit shift. 32 | func (n nv) shift11() nv { 33 | return ((n << 11) & (1<<32 - 1)) | ((n >> (32 - 11)) & (1<<32 - 1)) 34 | } 35 | 36 | // Seq contains iteration numbers used in the encryption function 37 | // itself. For example 28147 encryption and decryption process differs 38 | // only with this sequence. 39 | type Seq []uint8 40 | 41 | var ( 42 | SeqEncrypt = Seq([]uint8{ 43 | 0, 1, 2, 3, 4, 5, 6, 7, 44 | 0, 1, 2, 3, 4, 5, 6, 7, 45 | 0, 1, 2, 3, 4, 5, 6, 7, 46 | 7, 6, 5, 4, 3, 2, 1, 0, 47 | }) 48 | SeqDecrypt = Seq([]uint8{ 49 | 0, 1, 2, 3, 4, 5, 6, 7, 50 | 7, 6, 5, 4, 3, 2, 1, 0, 51 | 7, 6, 5, 4, 3, 2, 1, 0, 52 | 7, 6, 5, 4, 3, 2, 1, 0, 53 | }) 54 | ) 55 | 56 | type Cipher struct { 57 | key *[KeySize]byte 58 | sbox *Sbox 59 | x [8]nv 60 | } 61 | 62 | func NewCipher(key [KeySize]byte, sbox *Sbox) *Cipher { 63 | c := Cipher{} 64 | c.key = &key 65 | c.sbox = sbox 66 | c.x = [8]nv{ 67 | nv(key[0]) | nv(key[1])<<8 | nv(key[2])<<16 | nv(key[3])<<24, 68 | nv(key[4]) | nv(key[5])<<8 | nv(key[6])<<16 | nv(key[7])<<24, 69 | nv(key[8]) | nv(key[9])<<8 | nv(key[10])<<16 | nv(key[11])<<24, 70 | nv(key[12]) | nv(key[13])<<8 | nv(key[14])<<16 | nv(key[15])<<24, 71 | nv(key[16]) | nv(key[17])<<8 | nv(key[18])<<16 | nv(key[19])<<24, 72 | nv(key[20]) | nv(key[21])<<8 | nv(key[22])<<16 | nv(key[23])<<24, 73 | nv(key[24]) | nv(key[25])<<8 | nv(key[26])<<16 | nv(key[27])<<24, 74 | nv(key[28]) | nv(key[29])<<8 | nv(key[30])<<16 | nv(key[31])<<24, 75 | } 76 | return &c 77 | } 78 | 79 | func (c *Cipher) BlockSize() int { 80 | return BlockSize 81 | } 82 | 83 | // Convert binary byte block to two 32-bit internal integers. 84 | func block2nvs(b []byte) (n1, n2 nv) { 85 | n1 = nv(b[0]) | nv(b[1])<<8 | nv(b[2])<<16 | nv(b[3])<<24 86 | n2 = nv(b[4]) | nv(b[5])<<8 | nv(b[6])<<16 | nv(b[7])<<24 87 | return 88 | } 89 | 90 | // Convert two 32-bit internal integers to binary byte block. 91 | func nvs2block(n1, n2 nv, b []byte) { 92 | b[0] = byte((n2 >> 0) & 255) 93 | b[1] = byte((n2 >> 8) & 255) 94 | b[2] = byte((n2 >> 16) & 255) 95 | b[3] = byte((n2 >> 24) & 255) 96 | b[4] = byte((n1 >> 0) & 255) 97 | b[5] = byte((n1 >> 8) & 255) 98 | b[6] = byte((n1 >> 16) & 255) 99 | b[7] = byte((n1 >> 24) & 255) 100 | } 101 | 102 | func (c *Cipher) xcrypt(seq Seq, n1, n2 nv) (nv, nv) { 103 | for _, i := range seq { 104 | n1, n2 = c.sbox.k(n1+c.x[i]).shift11()^n2, n1 105 | } 106 | return n1, n2 107 | } 108 | 109 | // Encrypt single block. 110 | // If provided slices are shorter than the block size, then it will panic. 111 | func (c *Cipher) Encrypt(dst, src []byte) { 112 | n1, n2 := block2nvs(src) 113 | n1, n2 = c.xcrypt(SeqEncrypt, n1, n2) 114 | nvs2block(n1, n2, dst) 115 | } 116 | 117 | // Decrypt single block. 118 | // If provided slices are shorter than the block size, then it will panic. 119 | func (c *Cipher) Decrypt(dst, src []byte) { 120 | n1, n2 := block2nvs(src) 121 | n1, n2 = c.xcrypt(SeqDecrypt, n1, n2) 122 | nvs2block(n1, n2, dst) 123 | } 124 | -------------------------------------------------------------------------------- /gost28147/cipher_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "crypto/cipher" 22 | "crypto/rand" 23 | "testing" 24 | ) 25 | 26 | func TestCipherInterface(t *testing.T) { 27 | var key [32]byte 28 | var _ cipher.Block = NewCipher(key, SboxDefault) 29 | } 30 | 31 | func BenchmarkCipher(b *testing.B) { 32 | var key [KeySize]byte 33 | rand.Read(key[:]) 34 | dst := make([]byte, BlockSize) 35 | src := make([]byte, BlockSize) 36 | rand.Read(src) 37 | c := NewCipher(key, SboxDefault) 38 | b.ResetTimer() 39 | for i := 0; i < b.N; i++ { 40 | c.Encrypt(dst, src) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gost28147/ctr.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | type CTR struct { 21 | c *Cipher 22 | n1 nv 23 | n2 nv 24 | } 25 | 26 | func (c *Cipher) NewCTR(iv [BlockSize]byte) *CTR { 27 | n1, n2 := block2nvs(iv[:]) 28 | n2, n1 = c.xcrypt(SeqEncrypt, n1, n2) 29 | return &CTR{c, n1, n2} 30 | } 31 | 32 | func (c *CTR) XORKeyStream(dst, src []byte) { 33 | var n1t nv 34 | var n2t nv 35 | block := make([]byte, BlockSize) 36 | i := 0 37 | var n int 38 | MainLoop: 39 | for { 40 | c.n1 += 0x01010101 // C2 41 | c.n2 += 0x01010104 // C1 42 | if c.n2 >= 1<<32-1 { 43 | c.n2 -= 1<<32 - 1 44 | } 45 | n1t, n2t = c.c.xcrypt(SeqEncrypt, c.n1, c.n2) 46 | nvs2block(n1t, n2t, block) 47 | for n = 0; n < BlockSize; n++ { 48 | if i*BlockSize+n == len(src) { 49 | break MainLoop 50 | } 51 | dst[i*BlockSize+n] = src[i*BlockSize+n] ^ block[n] 52 | } 53 | i++ 54 | } 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /gost28147/ctr_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "bytes" 22 | "crypto/cipher" 23 | "crypto/rand" 24 | "testing" 25 | "testing/quick" 26 | ) 27 | 28 | func TestCTRGCL3Vector(t *testing.T) { 29 | sbox := &Gost2814789_TestParamSet 30 | key := [KeySize]byte{ 31 | 0x04, 0x75, 0xf6, 0xe0, 0x50, 0x38, 0xfb, 0xfa, 32 | 0xd2, 0xc7, 0xc3, 0x90, 0xed, 0xb3, 0xca, 0x3d, 33 | 0x15, 0x47, 0x12, 0x42, 0x91, 0xae, 0x1e, 0x8a, 34 | 0x2f, 0x79, 0xcd, 0x9e, 0xd2, 0xbc, 0xef, 0xbd, 35 | } 36 | plaintext := []byte{ 37 | 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 38 | 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 39 | 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 40 | 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 41 | 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 42 | 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 43 | 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 44 | 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 45 | 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 46 | 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 47 | 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 48 | 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 49 | 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 50 | 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 51 | 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 52 | 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 53 | 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 54 | 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 55 | 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 56 | 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 57 | 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, 58 | 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8, 59 | 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 60 | 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, 61 | 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 62 | 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 63 | 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, 64 | 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8, 65 | 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 66 | 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, 67 | 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, 68 | 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 69 | } 70 | ciphertext := []byte{ 71 | 0x4a, 0x5e, 0x37, 0x6c, 0xa1, 0x12, 0xd3, 0x55, 72 | 0x09, 0x13, 0x1a, 0x21, 0xac, 0xfb, 0xb2, 0x1e, 73 | 0x8c, 0x24, 0x9b, 0x57, 0x20, 0x68, 0x46, 0xd5, 74 | 0x23, 0x2a, 0x26, 0x35, 0x12, 0x56, 0x5c, 0x69, 75 | 0x2a, 0x2f, 0xd1, 0xab, 0xbd, 0x45, 0xdc, 0x3a, 76 | 0x1a, 0xa4, 0x57, 0x64, 0xd5, 0xe4, 0x69, 0x6d, 77 | 0xb4, 0x8b, 0xf1, 0x54, 0x78, 0x3b, 0x10, 0x8f, 78 | 0x7a, 0x4b, 0x32, 0xe0, 0xe8, 0x4c, 0xbf, 0x03, 79 | 0x24, 0x37, 0x95, 0x6a, 0x55, 0xa8, 0xce, 0x6f, 80 | 0x95, 0x62, 0x12, 0xf6, 0x79, 0xe6, 0xf0, 0x1b, 81 | 0x86, 0xef, 0x36, 0x36, 0x05, 0xd8, 0x6f, 0x10, 82 | 0xa1, 0x41, 0x05, 0x07, 0xf8, 0xfa, 0xa4, 0x0b, 83 | 0x17, 0x2c, 0x71, 0xbc, 0x8b, 0xcb, 0xcf, 0x3d, 84 | 0x74, 0x18, 0x32, 0x0b, 0x1c, 0xd2, 0x9e, 0x75, 85 | 0xba, 0x3e, 0x61, 0xe1, 0x61, 0x96, 0xd0, 0xee, 86 | 0x8f, 0xf2, 0x9a, 0x5e, 0xb7, 0x7a, 0x15, 0xaa, 87 | 0x4e, 0x1e, 0x77, 0x7c, 0x99, 0xe1, 0x41, 0x13, 88 | 0xf4, 0x60, 0x39, 0x46, 0x4c, 0x35, 0xde, 0x95, 89 | 0xcc, 0x4f, 0xd5, 0xaf, 0xd1, 0x4d, 0x84, 0x1a, 90 | 0x45, 0xc7, 0x2a, 0xf2, 0x2c, 0xc0, 0xb7, 0x94, 91 | 0xa3, 0x08, 0xb9, 0x12, 0x96, 0xb5, 0x97, 0x99, 92 | 0x3a, 0xb7, 0x0c, 0x14, 0x56, 0xb9, 0xcb, 0x49, 93 | 0x44, 0xa9, 0x93, 0xa9, 0xfb, 0x19, 0x10, 0x8c, 94 | 0x6a, 0x68, 0xe8, 0x7b, 0x06, 0x57, 0xf0, 0xef, 95 | 0x88, 0x44, 0xa6, 0xd2, 0x98, 0xbe, 0xd4, 0x07, 96 | 0x41, 0x37, 0x45, 0xa6, 0x71, 0x36, 0x76, 0x69, 97 | 0x4b, 0x75, 0x15, 0x33, 0x90, 0x29, 0x6e, 0x33, 98 | 0xcb, 0x96, 0x39, 0x78, 0x19, 0x2e, 0x96, 0xf3, 99 | 0x49, 0x4c, 0x89, 0x3d, 0xa1, 0x86, 0x82, 0x00, 100 | 0xce, 0xbd, 0x54, 0x29, 0x65, 0x00, 0x1d, 0x16, 101 | 0x13, 0xc3, 0xfe, 0x1f, 0x8c, 0x55, 0x63, 0x09, 102 | 0x1f, 0xcd, 0xd4, 0x28, 0xca, 103 | } 104 | iv := [8]byte{0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01} 105 | c := NewCipher(key, sbox) 106 | ctr := c.NewCTR(iv) 107 | tmp := make([]byte, len(plaintext)) 108 | ctr.XORKeyStream(tmp, plaintext) 109 | if bytes.Compare(tmp, ciphertext) != 0 { 110 | t.Fail() 111 | } 112 | ctr = c.NewCTR(iv) 113 | ctr.XORKeyStream(tmp, tmp) 114 | if bytes.Compare(tmp, plaintext) != 0 { 115 | t.Fail() 116 | } 117 | } 118 | 119 | func TestCTRGCL2Vector(t *testing.T) { 120 | sbox := &Gost2814789_TestParamSet 121 | key := [KeySize]byte{ 122 | 0xfc, 0x7a, 0xd2, 0x88, 0x6f, 0x45, 0x5b, 0x50, 123 | 0xd2, 0x90, 0x08, 0xfa, 0x62, 0x2b, 0x57, 0xd5, 124 | 0xc6, 0x5b, 0x3c, 0x63, 0x72, 0x02, 0x02, 0x57, 125 | 0x99, 0xca, 0xdf, 0x07, 0x68, 0x51, 0x9e, 0x8a, 126 | } 127 | plaintext := []byte{ 128 | 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 129 | 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 130 | 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 131 | 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 132 | 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 133 | 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 134 | 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 135 | } 136 | ciphertext := []byte{ 137 | 0xd0, 0xbe, 0x60, 0x1a, 0x2c, 0xf1, 0x90, 0x26, 138 | 0x9b, 0x7b, 0x23, 0xb4, 0xd2, 0xcc, 0xe1, 0x15, 139 | 0xf6, 0x05, 0x57, 0x28, 0x88, 0x75, 0xeb, 0x1e, 140 | 0xd3, 0x62, 0xdc, 0xda, 0x9b, 0x62, 0xee, 0x9a, 141 | 0x57, 0x87, 0x8a, 0xf1, 0x82, 0x37, 0x9c, 0x7f, 142 | 0x13, 0xcc, 0x55, 0x38, 0xb5, 0x63, 0x32, 0xc5, 143 | 0x23, 0xa4, 0xcb, 0x7d, 0x51, 144 | } 145 | var iv [8]byte 146 | c := NewCipher(key, sbox) 147 | ctr := c.NewCTR(iv) 148 | tmp := make([]byte, len(plaintext)) 149 | ctr.XORKeyStream(tmp, plaintext) 150 | if bytes.Compare(tmp, ciphertext) != 0 { 151 | t.Fail() 152 | } 153 | ctr = c.NewCTR(iv) 154 | ctr.XORKeyStream(tmp, tmp) 155 | if bytes.Compare(tmp, plaintext) != 0 { 156 | t.Fail() 157 | } 158 | } 159 | 160 | func TestCTRRandom(t *testing.T) { 161 | var key [KeySize]byte 162 | rand.Read(key[:]) 163 | c := NewCipher(key, SboxDefault) 164 | f := func(ivRaw []byte, pt []byte) bool { 165 | if len(pt) == 0 || len(ivRaw) < 8 { 166 | return true 167 | } 168 | var iv [8]byte 169 | copy(iv[:], ivRaw[:8]) 170 | tmp := make([]byte, len(pt)) 171 | ctr := c.NewCTR(iv) 172 | ctr.XORKeyStream(tmp, pt) 173 | ctr = c.NewCTR(iv) 174 | ctr.XORKeyStream(tmp, tmp) 175 | return bytes.Compare(tmp, pt) == 0 176 | } 177 | if err := quick.Check(f, nil); err != nil { 178 | t.Error(err) 179 | } 180 | } 181 | func TestCTRInterface(t *testing.T) { 182 | var key [32]byte 183 | var iv [8]byte 184 | c := NewCipher(key, SboxDefault) 185 | var _ cipher.Stream = c.NewCTR(iv) 186 | } 187 | 188 | func BenchmarkCTR(b *testing.B) { 189 | var key [KeySize]byte 190 | var iv [BlockSize]byte 191 | rand.Read(key[:]) 192 | rand.Read(iv[:]) 193 | dst := make([]byte, BlockSize) 194 | src := make([]byte, BlockSize) 195 | rand.Read(src) 196 | c := NewCipher(key, SboxDefault) 197 | ctr := c.NewCTR(iv) 198 | b.ResetTimer() 199 | for i := 0; i < b.N; i++ { 200 | ctr.XORKeyStream(dst, src) 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /gost28147/ecb.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | type ECBEncrypter struct { 21 | c *Cipher 22 | } 23 | 24 | func (c *Cipher) NewECBEncrypter() *ECBEncrypter { 25 | e := ECBEncrypter{c} 26 | return &e 27 | } 28 | 29 | func (e *ECBEncrypter) CryptBlocks(dst, src []byte) { 30 | for i := 0; i < len(src); i += BlockSize { 31 | e.c.Encrypt(dst[i:i+BlockSize], src[i:i+BlockSize]) 32 | } 33 | } 34 | 35 | func (e *ECBEncrypter) BlockSize() int { 36 | return e.c.BlockSize() 37 | } 38 | 39 | type ECBDecrypter struct { 40 | c *Cipher 41 | } 42 | 43 | func (c *Cipher) NewECBDecrypter() *ECBDecrypter { 44 | d := ECBDecrypter{c} 45 | return &d 46 | } 47 | 48 | func (e *ECBDecrypter) CryptBlocks(dst, src []byte) { 49 | for i := 0; i < len(src); i += BlockSize { 50 | e.c.Decrypt(dst[i:i+BlockSize], src[i:i+BlockSize]) 51 | } 52 | } 53 | 54 | func (e *ECBDecrypter) BlockSize() int { 55 | return e.c.BlockSize() 56 | } 57 | -------------------------------------------------------------------------------- /gost28147/ecb_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "bytes" 22 | "crypto/cipher" 23 | "testing" 24 | ) 25 | 26 | func TestECBGCL3Vectors(t *testing.T) { 27 | key := [KeySize]byte{ 28 | 0x04, 0x75, 0xf6, 0xe0, 0x50, 0x38, 0xfb, 0xfa, 29 | 0xd2, 0xc7, 0xc3, 0x90, 0xed, 0xb3, 0xca, 0x3d, 30 | 0x15, 0x47, 0x12, 0x42, 0x91, 0xae, 0x1e, 0x8a, 31 | 0x2f, 0x79, 0xcd, 0x9e, 0xd2, 0xbc, 0xef, 0xbd, 32 | } 33 | c := NewCipher(key, &Gost2814789_TestParamSet) 34 | plaintext := []byte{ 35 | 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 36 | 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 37 | 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 38 | 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 39 | 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 40 | 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 41 | 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 42 | 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 43 | 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 44 | 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 45 | 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 46 | 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 47 | 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 48 | 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 49 | 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 50 | 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 51 | 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 52 | 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 53 | 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 54 | 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 55 | 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, 56 | 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8, 57 | 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 58 | 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, 59 | 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 60 | 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 61 | 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, 62 | 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8, 63 | 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 64 | 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, 65 | 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, 66 | 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 67 | } 68 | ciphertext := []byte{ 69 | 0x4b, 0x8c, 0x4c, 0x98, 0x15, 0xf2, 0x4a, 0xea, 70 | 0x1e, 0xc3, 0x57, 0x09, 0xb3, 0xbc, 0x2e, 0xd1, 71 | 0xe0, 0xd1, 0xf2, 0x22, 0x65, 0x2d, 0x59, 0x18, 72 | 0xf7, 0xdf, 0xfc, 0x80, 0x4b, 0xde, 0x5c, 0x68, 73 | 0x46, 0x53, 0x75, 0x53, 0xa7, 0x46, 0x0d, 0xec, 74 | 0x05, 0x1f, 0x1b, 0xd3, 0x0a, 0x63, 0x1a, 0xb7, 75 | 0x78, 0xc4, 0x43, 0xe0, 0x5d, 0x3e, 0xa4, 0x0e, 76 | 0x2d, 0x7e, 0x23, 0xa9, 0x1b, 0xc9, 0x02, 0xbc, 77 | 0x21, 0x0c, 0x84, 0xcb, 0x0d, 0x0a, 0x07, 0xc8, 78 | 0x7b, 0xd0, 0xfb, 0xb5, 0x1a, 0x14, 0x04, 0x5c, 79 | 0xa2, 0x53, 0x97, 0x71, 0x2e, 0x5c, 0xc2, 0x8f, 80 | 0x39, 0x3f, 0x6f, 0x52, 0xf2, 0x30, 0x26, 0x4e, 81 | 0x8c, 0xe0, 0xd1, 0x01, 0x75, 0x6d, 0xdc, 0xd3, 82 | 0x03, 0x79, 0x1e, 0xca, 0xd5, 0xc1, 0x0e, 0x12, 83 | 0x53, 0x0a, 0x78, 0xe2, 0x0a, 0xb1, 0x1c, 0xea, 84 | 0x3a, 0xf8, 0x55, 0xb9, 0x7c, 0xe1, 0x0b, 0xba, 85 | 0xa0, 0xc8, 0x96, 0xeb, 0x50, 0x5a, 0xd3, 0x60, 86 | 0x43, 0xa3, 0x0f, 0x98, 0xdb, 0xd9, 0x50, 0x6d, 87 | 0x63, 0x91, 0xaf, 0x01, 0x40, 0xe9, 0x75, 0x5a, 88 | 0x46, 0x5c, 0x1f, 0x19, 0x4a, 0x0b, 0x89, 0x9b, 89 | 0xc4, 0xf6, 0xf8, 0xf5, 0x2f, 0x87, 0x3f, 0xfa, 90 | 0x26, 0xd4, 0xf8, 0x25, 0xba, 0x1f, 0x98, 0x82, 91 | 0xfc, 0x26, 0xaf, 0x2d, 0xc0, 0xf9, 0xc4, 0x58, 92 | 0x49, 0xfa, 0x09, 0x80, 0x02, 0x62, 0xa4, 0x34, 93 | 0x2d, 0xcb, 0x5a, 0x6b, 0xab, 0x61, 0x5d, 0x08, 94 | 0xd4, 0x26, 0xe0, 0x08, 0x13, 0xd6, 0x2e, 0x02, 95 | 0x2a, 0x37, 0xe8, 0xd0, 0xcf, 0x36, 0xf1, 0xc7, 96 | 0xc0, 0x3f, 0x9b, 0x21, 0x60, 0xbd, 0x29, 0x2d, 97 | 0x2e, 0x01, 0x48, 0x4e, 0xf8, 0x8f, 0x20, 0x16, 98 | 0x8a, 0xbf, 0x82, 0xdc, 0x32, 0x7a, 0xa3, 0x18, 99 | 0x69, 0xd1, 0x50, 0x59, 0x31, 0x91, 0xf2, 0x6c, 100 | 0x5a, 0x5f, 0xca, 0x58, 0x9a, 0xb2, 0x2d, 0xb2, 101 | } 102 | e := c.NewECBEncrypter() 103 | tmp := make([]byte, len(plaintext)) 104 | e.CryptBlocks(tmp, plaintext) 105 | if bytes.Compare(tmp, ciphertext) != 0 { 106 | t.Fail() 107 | } 108 | d := c.NewECBDecrypter() 109 | d.CryptBlocks(tmp, tmp) 110 | if bytes.Compare(tmp, plaintext) != 0 { 111 | t.Fail() 112 | } 113 | } 114 | 115 | // Crypto++ 5.6.2 test vectors 116 | func TestECBCryptoPPVectors(t *testing.T) { 117 | sbox := &AppliedCryptographyParamSet 118 | var key [KeySize]byte 119 | var pt [BlockSize]byte 120 | var ct [BlockSize]byte 121 | tmp := make([]byte, BlockSize) 122 | var c *Cipher 123 | 124 | key = [KeySize]byte{ 125 | 0xBE, 0x5E, 0xC2, 0x00, 0x6C, 0xFF, 0x9D, 0xCF, 126 | 0x52, 0x35, 0x49, 0x59, 0xF1, 0xFF, 0x0C, 0xBF, 127 | 0xE9, 0x50, 0x61, 0xB5, 0xA6, 0x48, 0xC1, 0x03, 128 | 0x87, 0x06, 0x9C, 0x25, 0x99, 0x7C, 0x06, 0x72, 129 | } 130 | pt = [BlockSize]byte{0x0D, 0xF8, 0x28, 0x02, 0xB7, 0x41, 0xA2, 0x92} 131 | ct = [BlockSize]byte{0x07, 0xF9, 0x02, 0x7D, 0xF7, 0xF7, 0xDF, 0x89} 132 | c = NewCipher(key, sbox) 133 | c.Encrypt(tmp, pt[:]) 134 | if bytes.Compare(tmp, ct[:]) != 0 { 135 | t.Fail() 136 | } 137 | 138 | key = [KeySize]byte{ 139 | 0xB3, 0x85, 0x27, 0x2A, 0xC8, 0xD7, 0x2A, 0x5A, 140 | 0x8B, 0x34, 0x4B, 0xC8, 0x03, 0x63, 0xAC, 0x4D, 141 | 0x09, 0xBF, 0x58, 0xF4, 0x1F, 0x54, 0x06, 0x24, 142 | 0xCB, 0xCB, 0x8F, 0xDC, 0xF5, 0x53, 0x07, 0xD7, 143 | } 144 | pt = [BlockSize]byte{0x13, 0x54, 0xEE, 0x9C, 0x0A, 0x11, 0xCD, 0x4C} 145 | ct = [BlockSize]byte{0x4F, 0xB5, 0x05, 0x36, 0xF9, 0x60, 0xA7, 0xB1} 146 | c = NewCipher(key, sbox) 147 | c.Encrypt(tmp, pt[:]) 148 | if bytes.Compare(tmp, ct[:]) != 0 { 149 | t.Fail() 150 | } 151 | 152 | key = [KeySize]byte{ 153 | 0xAE, 0xE0, 0x2F, 0x60, 0x9A, 0x35, 0x66, 0x0E, 154 | 0x40, 0x97, 0xE5, 0x46, 0xFD, 0x30, 0x26, 0xB0, 155 | 0x32, 0xCD, 0x10, 0x7C, 0x7D, 0x45, 0x99, 0x77, 156 | 0xAD, 0xF4, 0x89, 0xBE, 0xF2, 0x65, 0x22, 0x62, 157 | } 158 | pt = [BlockSize]byte{0x66, 0x93, 0xD4, 0x92, 0xC4, 0xB0, 0xCC, 0x39} 159 | ct = [BlockSize]byte{0x67, 0x00, 0x34, 0xAC, 0x0F, 0xA8, 0x11, 0xB5} 160 | c = NewCipher(key, sbox) 161 | c.Encrypt(tmp, pt[:]) 162 | if bytes.Compare(tmp, ct[:]) != 0 { 163 | t.Fail() 164 | } 165 | 166 | key = [KeySize]byte{ 167 | 0x32, 0x0E, 0x9D, 0x84, 0x22, 0x16, 0x5D, 0x58, 168 | 0x91, 0x1D, 0xFC, 0x7D, 0x8B, 0xBB, 0x1F, 0x81, 169 | 0xB0, 0xEC, 0xD9, 0x24, 0x02, 0x3B, 0xF9, 0x4D, 170 | 0x9D, 0xF7, 0xDC, 0xF7, 0x80, 0x12, 0x40, 0xE0, 171 | } 172 | pt = [BlockSize]byte{0x99, 0xE2, 0xD1, 0x30, 0x80, 0x92, 0x8D, 0x79} 173 | ct = [BlockSize]byte{0x81, 0x18, 0xFF, 0x9D, 0x3B, 0x3C, 0xFE, 0x7D} 174 | c = NewCipher(key, sbox) 175 | c.Encrypt(tmp, pt[:]) 176 | if bytes.Compare(tmp, ct[:]) != 0 { 177 | t.Fail() 178 | } 179 | 180 | key = [KeySize]byte{ 181 | 0xC9, 0xF7, 0x03, 0xBB, 0xBF, 0xC6, 0x36, 0x91, 182 | 0xBF, 0xA3, 0xB7, 0xB8, 0x7E, 0xA8, 0xFD, 0x5E, 183 | 0x8E, 0x8E, 0xF3, 0x84, 0xEF, 0x73, 0x3F, 0x1A, 184 | 0x61, 0xAE, 0xF6, 0x8C, 0x8F, 0xFA, 0x26, 0x5F, 185 | } 186 | pt = [BlockSize]byte{0xD1, 0xE7, 0x87, 0x74, 0x9C, 0x72, 0x81, 0x4C} 187 | ct = [BlockSize]byte{0xA0, 0x83, 0x82, 0x6A, 0x79, 0x0D, 0x3E, 0x0C} 188 | c = NewCipher(key, sbox) 189 | c.Encrypt(tmp, pt[:]) 190 | if bytes.Compare(tmp, ct[:]) != 0 { 191 | t.Fail() 192 | } 193 | 194 | key = [KeySize]byte{ 195 | 0x72, 0x8F, 0xEE, 0x32, 0xF0, 0x4B, 0x4C, 0x65, 196 | 0x4A, 0xD7, 0xF6, 0x07, 0xD7, 0x1C, 0x66, 0x0C, 197 | 0x2C, 0x26, 0x70, 0xD7, 0xC9, 0x99, 0x71, 0x32, 198 | 0x33, 0x14, 0x9A, 0x1C, 0x0C, 0x17, 0xA1, 0xF0, 199 | } 200 | pt = [BlockSize]byte{0xD4, 0xC0, 0x53, 0x23, 0xA4, 0xF7, 0xA7, 0xB5} 201 | ct = [BlockSize]byte{0x4D, 0x1F, 0x2E, 0x6B, 0x0D, 0x9D, 0xE2, 0xCE} 202 | c = NewCipher(key, sbox) 203 | c.Encrypt(tmp, pt[:]) 204 | if bytes.Compare(tmp, ct[:]) != 0 { 205 | t.Fail() 206 | } 207 | 208 | key = [KeySize]byte{ 209 | 0x35, 0xFC, 0x96, 0x40, 0x22, 0x09, 0x50, 0x0F, 210 | 0xCF, 0xDE, 0xF5, 0x35, 0x2D, 0x1A, 0xBB, 0x03, 211 | 0x8F, 0xE3, 0x3F, 0xC0, 0xD9, 0xD5, 0x85, 0x12, 212 | 0xE5, 0x63, 0x70, 0xB2, 0x2B, 0xAA, 0x13, 0x3B, 213 | } 214 | pt = [BlockSize]byte{0x87, 0x42, 0xD9, 0xA0, 0x5F, 0x6A, 0x3A, 0xF6} 215 | ct = [BlockSize]byte{0x2F, 0x3B, 0xB8, 0x48, 0x79, 0xD1, 0x1E, 0x52} 216 | c = NewCipher(key, sbox) 217 | c.Encrypt(tmp, pt[:]) 218 | if bytes.Compare(tmp, ct[:]) != 0 { 219 | t.Fail() 220 | } 221 | 222 | key = [KeySize]byte{ 223 | 0xD4, 0x16, 0xF6, 0x30, 0xBE, 0x65, 0xB7, 0xFE, 224 | 0x15, 0x06, 0x56, 0x18, 0x33, 0x70, 0xE0, 0x70, 225 | 0x18, 0x23, 0x4E, 0xE5, 0xDA, 0x3D, 0x89, 0xC4, 226 | 0xCE, 0x91, 0x52, 0xA0, 0x3E, 0x5B, 0xFB, 0x77, 227 | } 228 | pt = [BlockSize]byte{0xF8, 0x65, 0x06, 0xDA, 0x04, 0xE4, 0x1C, 0xB8} 229 | ct = [BlockSize]byte{0x96, 0xF0, 0xA5, 0xC7, 0x7A, 0x04, 0xF5, 0xCE} 230 | c = NewCipher(key, sbox) 231 | c.Encrypt(tmp, pt[:]) 232 | if bytes.Compare(tmp, ct[:]) != 0 { 233 | t.Fail() 234 | } 235 | } 236 | 237 | // http://cryptomanager.com/tv.html test vectors. 238 | func TestECBCryptomanager(t *testing.T) { 239 | sbox := &GostR3411_94_TestParamSet 240 | key := [KeySize]byte{ 241 | 0x75, 0x71, 0x31, 0x34, 0xB6, 0x0F, 0xEC, 0x45, 242 | 0xA6, 0x07, 0xBB, 0x83, 0xAA, 0x37, 0x46, 0xAF, 243 | 0x4F, 0xF9, 0x9D, 0xA6, 0xD1, 0xB5, 0x3B, 0x5B, 244 | 0x1B, 0x40, 0x2A, 0x1B, 0xAA, 0x03, 0x0D, 0x1B, 245 | } 246 | c := NewCipher(key, sbox) 247 | tmp := make([]byte, BlockSize) 248 | c.Encrypt(tmp, []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) 249 | if bytes.Compare(tmp, []byte{0x03, 0x25, 0x1E, 0x14, 0xF9, 0xD2, 0x8A, 0xCB}) != 0 { 250 | t.Fail() 251 | } 252 | } 253 | 254 | func TestECBInterface(t *testing.T) { 255 | var key [32]byte 256 | c := NewCipher(key, SboxDefault) 257 | var _ cipher.BlockMode = c.NewECBEncrypter() 258 | var _ cipher.BlockMode = c.NewECBDecrypter() 259 | } 260 | -------------------------------------------------------------------------------- /gost28147/mac.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "errors" 22 | ) 23 | 24 | var ( 25 | SeqMAC = Seq([]uint8{ 26 | 0, 1, 2, 3, 4, 5, 6, 7, 27 | 0, 1, 2, 3, 4, 5, 6, 7, 28 | }) 29 | ) 30 | 31 | type MAC struct { 32 | c *Cipher 33 | size int 34 | iv []byte 35 | prev []byte 36 | buf []byte 37 | n1 nv 38 | n2 nv 39 | } 40 | 41 | // Create MAC with given tag size and initial initialization vector. 42 | // Size is in bytes and must be between 1 and 8. To be RFC conformant, 43 | // iv must be the first block of the authenticated data, second and 44 | // following ones are fed to Write function. 45 | func (c *Cipher) NewMAC(size int, iv [BlockSize]byte) (*MAC, error) { 46 | if size == 0 || size > 8 { 47 | return nil, errors.New("Invalid tag size") 48 | } 49 | m := MAC{c: c, size: size, iv: iv[:]} 50 | n2, n1 := block2nvs(iv[:]) 51 | m.iv = make([]byte, BlockSize) 52 | nvs2block(n1, n2, m.iv) 53 | m.prev = make([]byte, BlockSize) 54 | m.Reset() 55 | return &m, nil 56 | } 57 | 58 | func (m *MAC) Reset() { 59 | copy(m.prev, m.iv) 60 | m.buf = nil 61 | } 62 | 63 | func (m *MAC) BlockSize() int { 64 | return BlockSize 65 | } 66 | 67 | func (m *MAC) Size() int { 68 | return m.size 69 | } 70 | 71 | func (m *MAC) Write(b []byte) (int, error) { 72 | m.buf = append(m.buf, b...) 73 | for len(m.buf) >= BlockSize { 74 | for i := 0; i < BlockSize; i++ { 75 | m.prev[i] ^= m.buf[i] 76 | } 77 | m.n1, m.n2 = block2nvs(m.prev) 78 | m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2) 79 | nvs2block(m.n2, m.n1, m.prev) 80 | m.buf = m.buf[8:] 81 | } 82 | return len(b), nil 83 | } 84 | 85 | func (m *MAC) Sum(b []byte) []byte { 86 | if len(m.buf) == 0 { 87 | return append(b, m.prev[0:m.size]...) 88 | } 89 | buf := m.buf 90 | var i int 91 | for i = 0; i < BlockSize-len(m.buf); i++ { 92 | buf = append(buf, byte(0)) 93 | } 94 | for i = 0; i < BlockSize; i++ { 95 | buf[i] ^= m.prev[i] 96 | } 97 | m.n1, m.n2 = block2nvs(buf) 98 | m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2) 99 | nvs2block(m.n2, m.n1, buf) 100 | return append(b, buf[0:m.size]...) 101 | } 102 | -------------------------------------------------------------------------------- /gost28147/mac_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | import ( 21 | "bytes" 22 | "crypto/rand" 23 | "hash" 24 | "testing" 25 | "testing/quick" 26 | ) 27 | 28 | func TestMACVectors(t *testing.T) { 29 | var key [KeySize]byte 30 | copy(key[:], []byte("This is message\xFF length\x0032 bytes")) 31 | c := NewCipher(key, SboxDefault) 32 | var iv [8]byte 33 | m, err := c.NewMAC(8, iv) 34 | if err != nil { 35 | t.Fail() 36 | } 37 | 38 | m.Write([]byte("a")) 39 | if bytes.Compare(m.Sum(nil), []byte{0xbd, 0x5d, 0x3b, 0x5b, 0x2b, 0x7b, 0x57, 0xaf}) != 0 { 40 | t.Fail() 41 | } 42 | 43 | m.Reset() 44 | m.Write([]byte("abc")) 45 | if bytes.Compare(m.Sum(nil), []byte{0x28, 0x66, 0x1e, 0x40, 0x80, 0x5b, 0x1f, 0xf9}) != 0 { 46 | t.Fail() 47 | } 48 | 49 | m.Reset() 50 | for i := 0; i < 128; i++ { 51 | m.Write([]byte("U")) 52 | } 53 | if bytes.Compare(m.Sum(nil), []byte{0x1a, 0x06, 0xd1, 0xba, 0xd7, 0x45, 0x80, 0xef}) != 0 { 54 | t.Fail() 55 | } 56 | 57 | m.Reset() 58 | for i := 0; i < 13; i++ { 59 | m.Write([]byte("x")) 60 | } 61 | if bytes.Compare(m.Sum(nil), []byte{0x91, 0x7e, 0xe1, 0xf1, 0xa6, 0x68, 0xfb, 0xd3}) != 0 { 62 | t.Fail() 63 | } 64 | } 65 | 66 | func TestMACRandom(t *testing.T) { 67 | var key [KeySize]byte 68 | rand.Read(key[:]) 69 | c := NewCipher(key, SboxDefault) 70 | f := func(ivRaw []byte, data []byte) bool { 71 | if len(data) == 0 { 72 | return true 73 | } 74 | var iv [8]byte 75 | if len(ivRaw) >= 8 { 76 | copy(iv[:], ivRaw[:8]) 77 | } 78 | m, err := c.NewMAC(8, iv) 79 | if err != nil { 80 | t.Fail() 81 | } 82 | 83 | var tag1 []byte 84 | var tag2 []byte 85 | 86 | for _, b := range data { 87 | m.Write([]byte{b}) 88 | } 89 | m.Sum(tag1) 90 | 91 | m.Reset() 92 | m.Write(data) 93 | m.Sum(tag2) 94 | 95 | return bytes.Compare(tag1, tag2) == 0 96 | } 97 | if err := quick.Check(f, nil); err != nil { 98 | t.Error(err) 99 | } 100 | } 101 | 102 | func TestMACInterface(t *testing.T) { 103 | var key [32]byte 104 | var iv [8]byte 105 | c := NewCipher(key, SboxDefault) 106 | m, _ := c.NewMAC(8, iv) 107 | var _ hash.Hash = m 108 | } 109 | 110 | func BenchmarkMAC(b *testing.B) { 111 | var key [KeySize]byte 112 | var iv [BlockSize]byte 113 | rand.Read(key[:]) 114 | rand.Read(iv[:]) 115 | b1 := make([]byte, BlockSize) 116 | b2 := make([]byte, BlockSize) 117 | rand.Read(b1) 118 | rand.Read(b2) 119 | c := NewCipher(key, SboxDefault) 120 | mac, _ := c.NewMAC(BlockSize, iv) 121 | b.ResetTimer() 122 | for i := 0; i < b.N; i++ { 123 | mac.Write(b1) 124 | mac.Write(b2) 125 | mac.Sum(nil) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /gost28147/sbox.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost28147 19 | 20 | // Sbox is a representation of eight substitution boxes. 21 | type Sbox [8][16]uint8 22 | 23 | var ( 24 | Gost2814789_TestParamSet = Sbox([8][16]uint8{ 25 | {4, 2, 15, 5, 9, 1, 0, 8, 14, 3, 11, 12, 13, 7, 10, 6}, 26 | {12, 9, 15, 14, 8, 1, 3, 10, 2, 7, 4, 13, 6, 0, 11, 5}, 27 | {13, 8, 14, 12, 7, 3, 9, 10, 1, 5, 2, 4, 6, 15, 0, 11}, 28 | {14, 9, 11, 2, 5, 15, 7, 1, 0, 13, 12, 6, 10, 4, 3, 8}, 29 | {3, 14, 5, 9, 6, 8, 0, 13, 10, 11, 7, 12, 2, 1, 15, 4}, 30 | {8, 15, 6, 11, 1, 9, 12, 5, 13, 3, 7, 10, 0, 14, 2, 4}, 31 | {9, 11, 12, 0, 3, 6, 7, 5, 4, 8, 14, 15, 1, 10, 2, 13}, 32 | {12, 6, 5, 2, 11, 0, 9, 13, 3, 14, 7, 10, 15, 4, 1, 8}, 33 | }) 34 | Gost28147_CryptoProParamSetA = Sbox([8][16]uint8{ 35 | {9, 6, 3, 2, 8, 11, 1, 7, 10, 4, 14, 15, 12, 0, 13, 5}, 36 | {3, 7, 14, 9, 8, 10, 15, 0, 5, 2, 6, 12, 11, 4, 13, 1}, 37 | {14, 4, 6, 2, 11, 3, 13, 8, 12, 15, 5, 10, 0, 7, 1, 9}, 38 | {14, 7, 10, 12, 13, 1, 3, 9, 0, 2, 11, 4, 15, 8, 5, 6}, 39 | {11, 5, 1, 9, 8, 13, 15, 0, 14, 4, 2, 3, 12, 7, 10, 6}, 40 | {3, 10, 13, 12, 1, 2, 0, 11, 7, 5, 9, 4, 8, 15, 14, 6}, 41 | {1, 13, 2, 9, 7, 10, 6, 0, 8, 12, 4, 5, 15, 3, 11, 14}, 42 | {11, 10, 15, 5, 0, 12, 14, 8, 6, 2, 3, 9, 1, 7, 13, 4}, 43 | }) 44 | Gost28147_CryptoProParamSetB = Sbox([8][16]uint8{ 45 | {8, 4, 11, 1, 3, 5, 0, 9, 2, 14, 10, 12, 13, 6, 7, 15}, 46 | {0, 1, 2, 10, 4, 13, 5, 12, 9, 7, 3, 15, 11, 8, 6, 14}, 47 | {14, 12, 0, 10, 9, 2, 13, 11, 7, 5, 8, 15, 3, 6, 1, 4}, 48 | {7, 5, 0, 13, 11, 6, 1, 2, 3, 10, 12, 15, 4, 14, 9, 8}, 49 | {2, 7, 12, 15, 9, 5, 10, 11, 1, 4, 0, 13, 6, 8, 14, 3}, 50 | {8, 3, 2, 6, 4, 13, 14, 11, 12, 1, 7, 15, 10, 0, 9, 5}, 51 | {5, 2, 10, 11, 9, 1, 12, 3, 7, 4, 13, 0, 6, 15, 8, 14}, 52 | {0, 4, 11, 14, 8, 3, 7, 1, 10, 2, 9, 6, 15, 13, 5, 12}, 53 | }) 54 | Gost28147_CryptoProParamSetC = Sbox([8][16]uint8{ 55 | {1, 11, 12, 2, 9, 13, 0, 15, 4, 5, 8, 14, 10, 7, 6, 3}, 56 | {0, 1, 7, 13, 11, 4, 5, 2, 8, 14, 15, 12, 9, 10, 6, 3}, 57 | {8, 2, 5, 0, 4, 9, 15, 10, 3, 7, 12, 13, 6, 14, 1, 11}, 58 | {3, 6, 0, 1, 5, 13, 10, 8, 11, 2, 9, 7, 14, 15, 12, 4}, 59 | {8, 13, 11, 0, 4, 5, 1, 2, 9, 3, 12, 14, 6, 15, 10, 7}, 60 | {12, 9, 11, 1, 8, 14, 2, 4, 7, 3, 6, 5, 10, 0, 15, 13}, 61 | {10, 9, 6, 8, 13, 14, 2, 0, 15, 3, 5, 11, 4, 1, 12, 7}, 62 | {7, 4, 0, 5, 10, 2, 15, 14, 12, 6, 1, 11, 13, 9, 3, 8}, 63 | }) 64 | Gost28147_CryptoProParamSetD = Sbox([8][16]uint8{ 65 | {15, 12, 2, 10, 6, 4, 5, 0, 7, 9, 14, 13, 1, 11, 8, 3}, 66 | {11, 6, 3, 4, 12, 15, 14, 2, 7, 13, 8, 0, 5, 10, 9, 1}, 67 | {1, 12, 11, 0, 15, 14, 6, 5, 10, 13, 4, 8, 9, 3, 7, 2}, 68 | {1, 5, 14, 12, 10, 7, 0, 13, 6, 2, 11, 4, 9, 3, 15, 8}, 69 | {0, 12, 8, 9, 13, 2, 10, 11, 7, 3, 6, 5, 4, 14, 15, 1}, 70 | {8, 0, 15, 3, 2, 5, 14, 11, 1, 10, 4, 7, 12, 9, 13, 6}, 71 | {3, 0, 6, 15, 1, 14, 9, 2, 13, 8, 12, 4, 11, 10, 5, 7}, 72 | {1, 10, 6, 8, 15, 11, 0, 4, 12, 3, 5, 9, 7, 13, 2, 14}, 73 | }) 74 | GostR3411_94_TestParamSet = Sbox([8][16]uint8{ 75 | {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3}, 76 | {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9}, 77 | {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11}, 78 | {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3}, 79 | {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2}, 80 | {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14}, 81 | {13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12}, 82 | {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12}, 83 | }) 84 | GostR3411_94_CryptoProParamSet = Sbox([8][16]uint8{ 85 | {10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15}, 86 | {5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8}, 87 | {7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13}, 88 | {4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3}, 89 | {7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5}, 90 | {7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3}, 91 | {13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11}, 92 | {1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12}, 93 | }) 94 | AppliedCryptographyParamSet = GostR3411_94_TestParamSet 95 | Gost28147_tc26_ParamZ = Sbox([8][16]uint8{ 96 | {12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1}, 97 | {6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15}, 98 | {11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0}, 99 | {12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11}, 100 | {7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12}, 101 | {5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0}, 102 | {8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7}, 103 | {1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2}, 104 | }) 105 | SboxDefault = &Gost28147_CryptoProParamSetA 106 | ) 107 | 108 | // Sbox substitution itself. 109 | func (s *Sbox) k(n nv) nv { 110 | return nv(s[0][(n>>0)&0x0F])<<0 + 111 | nv(s[1][(n>>4)&0x0F])<<4 + 112 | nv(s[2][(n>>8)&0x0F])<<8 + 113 | nv(s[3][(n>>12)&0x0F])<<12 + 114 | nv(s[4][(n>>16)&0x0F])<<16 + 115 | nv(s[5][(n>>20)&0x0F])<<20 + 116 | nv(s[6][(n>>24)&0x0F])<<24 + 117 | nv(s[7][(n>>28)&0x0F])<<28 118 | } 119 | -------------------------------------------------------------------------------- /gost3410/2001_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "bytes" 22 | "crypto/rand" 23 | "testing" 24 | "testing/quick" 25 | ) 26 | 27 | func TestRFCVectors(t *testing.T) { 28 | priv := []byte{ 29 | 0x28, 0x3b, 0xec, 0x91, 0x98, 0xce, 0x19, 0x1d, 30 | 0xee, 0x7e, 0x39, 0x49, 0x1f, 0x96, 0x60, 0x1b, 31 | 0xc1, 0x72, 0x9a, 0xd3, 0x9d, 0x35, 0xed, 0x10, 32 | 0xbe, 0xb9, 0x9b, 0x78, 0xde, 0x9a, 0x92, 0x7a, 33 | } 34 | pubX := []byte{ 35 | 0x0b, 0xd8, 0x6f, 0xe5, 0xd8, 0xdb, 0x89, 0x66, 36 | 0x8f, 0x78, 0x9b, 0x4e, 0x1d, 0xba, 0x85, 0x85, 37 | 0xc5, 0x50, 0x8b, 0x45, 0xec, 0x5b, 0x59, 0xd8, 38 | 0x90, 0x6d, 0xdb, 0x70, 0xe2, 0x49, 0x2b, 0x7f, 39 | } 40 | pubY := []byte{ 41 | 0xda, 0x77, 0xff, 0x87, 0x1a, 0x10, 0xfb, 0xdf, 42 | 0x27, 0x66, 0xd2, 0x93, 0xc5, 0xd1, 0x64, 0xaf, 43 | 0xbb, 0x3c, 0x7b, 0x97, 0x3a, 0x41, 0xc8, 0x85, 44 | 0xd1, 0x1d, 0x70, 0xd6, 0x89, 0xb4, 0xf1, 0x26, 45 | } 46 | digest := []byte{ 47 | 0x2d, 0xfb, 0xc1, 0xb3, 0x72, 0xd8, 0x9a, 0x11, 48 | 0x88, 0xc0, 0x9c, 0x52, 0xe0, 0xee, 0xc6, 0x1f, 49 | 0xce, 0x52, 0x03, 0x2a, 0xb1, 0x02, 0x2e, 0x8e, 50 | 0x67, 0xec, 0xe6, 0x67, 0x2b, 0x04, 0x3e, 0xe5, 51 | } 52 | signature := []byte{ 53 | 0x01, 0x45, 0x6c, 0x64, 0xba, 0x46, 0x42, 0xa1, 54 | 0x65, 0x3c, 0x23, 0x5a, 0x98, 0xa6, 0x02, 0x49, 55 | 0xbc, 0xd6, 0xd3, 0xf7, 0x46, 0xb6, 0x31, 0xdf, 56 | 0x92, 0x80, 0x14, 0xf6, 0xc5, 0xbf, 0x9c, 0x40, 57 | 0x41, 0xaa, 0x28, 0xd2, 0xf1, 0xab, 0x14, 0x82, 58 | 0x80, 0xcd, 0x9e, 0xd5, 0x6f, 0xed, 0xa4, 0x19, 59 | 0x74, 0x05, 0x35, 0x54, 0xa4, 0x27, 0x67, 0xb8, 60 | 0x3a, 0xd0, 0x43, 0xfd, 0x39, 0xdc, 0x04, 0x93, 61 | } 62 | 63 | c, err := NewCurveFromParams(CurveParamsGostR34102001Test) 64 | if err != nil { 65 | t.FailNow() 66 | } 67 | prv, err := NewPrivateKey(c, Mode2001, priv) 68 | if err != nil { 69 | t.FailNow() 70 | } 71 | pub, err := prv.PublicKey() 72 | if err != nil { 73 | t.FailNow() 74 | } 75 | if bytes.Compare(pub.Raw()[:32], pubX) != 0 { 76 | t.FailNow() 77 | } 78 | if bytes.Compare(pub.Raw()[32:], pubY) != 0 { 79 | t.FailNow() 80 | } 81 | ourSign, err := prv.SignDigest(digest, rand.Reader) 82 | if err != nil { 83 | t.FailNow() 84 | } 85 | valid, err := pub.VerifyDigest(digest, ourSign) 86 | if err != nil || !valid { 87 | t.FailNow() 88 | } 89 | valid, err = pub.VerifyDigest(digest, signature) 90 | if err != nil || !valid { 91 | t.FailNow() 92 | } 93 | } 94 | 95 | func TestRandom2001(t *testing.T) { 96 | c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) 97 | f := func(data [31]byte, digest [32]byte) bool { 98 | prv, err := NewPrivateKey( 99 | c, 100 | Mode2001, 101 | append([]byte{0xde}, data[:]...), 102 | ) 103 | if err != nil { 104 | return false 105 | } 106 | pub, err := prv.PublicKey() 107 | if err != nil { 108 | return false 109 | } 110 | pubRaw := pub.Raw() 111 | pub, err = NewPublicKey(c, Mode2001, pubRaw) 112 | if err != nil { 113 | return false 114 | } 115 | sign, err := prv.SignDigest(digest[:], rand.Reader) 116 | if err != nil { 117 | return false 118 | } 119 | valid, err := pub.VerifyDigest(digest[:], sign) 120 | if err != nil { 121 | return false 122 | } 123 | return valid 124 | } 125 | if err := quick.Check(f, nil); err != nil { 126 | t.Error(err) 127 | } 128 | } 129 | 130 | func BenchmarkSign2001(b *testing.B) { 131 | c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) 132 | prv, err := GenPrivateKey(c, Mode2001, rand.Reader) 133 | if err != nil { 134 | b.FailNow() 135 | } 136 | digest := make([]byte, 32) 137 | rand.Read(digest) 138 | b.ResetTimer() 139 | for i := 0; i < b.N; i++ { 140 | prv.SignDigest(digest, rand.Reader) 141 | } 142 | } 143 | 144 | func BenchmarkVerify2001(b *testing.B) { 145 | c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) 146 | prv, err := GenPrivateKey(c, Mode2001, rand.Reader) 147 | if err != nil { 148 | b.FailNow() 149 | } 150 | digest := make([]byte, 32) 151 | rand.Read(digest) 152 | sign, err := prv.SignDigest(digest, rand.Reader) 153 | if err != nil { 154 | b.FailNow() 155 | } 156 | pub, err := prv.PublicKey() 157 | if err != nil { 158 | b.FailNow() 159 | } 160 | b.ResetTimer() 161 | for i := 0; i < b.N; i++ { 162 | pub.VerifyDigest(digest, sign) 163 | } 164 | } 165 | 166 | func TestPrvEqualsTo1(t *testing.T) { 167 | c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) 168 | prv, err := NewPrivateKey(c, Mode2001, []byte{0x01}) 169 | if err != nil { 170 | t.FailNow() 171 | } 172 | pub, err := prv.PublicKey() 173 | if err != nil { 174 | t.FailNow() 175 | } 176 | digest := []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01} 177 | sign, err := prv.SignDigest(digest, rand.Reader) 178 | if err != nil { 179 | t.FailNow() 180 | } 181 | valid, err := pub.VerifyDigest(digest, sign) 182 | if err != nil || !valid { 183 | t.FailNow() 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /gost3410/2012_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "bytes" 22 | "crypto/rand" 23 | "testing" 24 | "testing/quick" 25 | ) 26 | 27 | func TestGCL3Vectors(t *testing.T) { 28 | p := []byte{ 29 | 0x45, 0x31, 0xAC, 0xD1, 0xFE, 0x00, 0x23, 0xC7, 30 | 0x55, 0x0D, 0x26, 0x7B, 0x6B, 0x2F, 0xEE, 0x80, 31 | 0x92, 0x2B, 0x14, 0xB2, 0xFF, 0xB9, 0x0F, 0x04, 32 | 0xD4, 0xEB, 0x7C, 0x09, 0xB5, 0xD2, 0xD1, 0x5D, 33 | 0xF1, 0xD8, 0x52, 0x74, 0x1A, 0xF4, 0x70, 0x4A, 34 | 0x04, 0x58, 0x04, 0x7E, 0x80, 0xE4, 0x54, 0x6D, 35 | 0x35, 0xB8, 0x33, 0x6F, 0xAC, 0x22, 0x4D, 0xD8, 36 | 0x16, 0x64, 0xBB, 0xF5, 0x28, 0xBE, 0x63, 0x73, 37 | } 38 | q := []byte{ 39 | 0x45, 0x31, 0xAC, 0xD1, 0xFE, 0x00, 0x23, 0xC7, 40 | 0x55, 0x0D, 0x26, 0x7B, 0x6B, 0x2F, 0xEE, 0x80, 41 | 0x92, 0x2B, 0x14, 0xB2, 0xFF, 0xB9, 0x0F, 0x04, 42 | 0xD4, 0xEB, 0x7C, 0x09, 0xB5, 0xD2, 0xD1, 0x5D, 43 | 0xA8, 0x2F, 0x2D, 0x7E, 0xCB, 0x1D, 0xBA, 0xC7, 44 | 0x19, 0x90, 0x5C, 0x5E, 0xEC, 0xC4, 0x23, 0xF1, 45 | 0xD8, 0x6E, 0x25, 0xED, 0xBE, 0x23, 0xC5, 0x95, 46 | 0xD6, 0x44, 0xAA, 0xF1, 0x87, 0xE6, 0xE6, 0xDF, 47 | } 48 | a := []byte{ 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 57 | } 58 | b := []byte{ 59 | 0x1C, 0xFF, 0x08, 0x06, 0xA3, 0x11, 0x16, 0xDA, 60 | 0x29, 0xD8, 0xCF, 0xA5, 0x4E, 0x57, 0xEB, 0x74, 61 | 0x8B, 0xC5, 0xF3, 0x77, 0xE4, 0x94, 0x00, 0xFD, 62 | 0xD7, 0x88, 0xB6, 0x49, 0xEC, 0xA1, 0xAC, 0x43, 63 | 0x61, 0x83, 0x40, 0x13, 0xB2, 0xAD, 0x73, 0x22, 64 | 0x48, 0x0A, 0x89, 0xCA, 0x58, 0xE0, 0xCF, 0x74, 65 | 0xBC, 0x9E, 0x54, 0x0C, 0x2A, 0xDD, 0x68, 0x97, 66 | 0xFA, 0xD0, 0xA3, 0x08, 0x4F, 0x30, 0x2A, 0xDC, 67 | } 68 | x := []byte{ 69 | 0x24, 0xD1, 0x9C, 0xC6, 0x45, 0x72, 0xEE, 0x30, 70 | 0xF3, 0x96, 0xBF, 0x6E, 0xBB, 0xFD, 0x7A, 0x6C, 71 | 0x52, 0x13, 0xB3, 0xB3, 0xD7, 0x05, 0x7C, 0xC8, 72 | 0x25, 0xF9, 0x10, 0x93, 0xA6, 0x8C, 0xD7, 0x62, 73 | 0xFD, 0x60, 0x61, 0x12, 0x62, 0xCD, 0x83, 0x8D, 74 | 0xC6, 0xB6, 0x0A, 0xA7, 0xEE, 0xE8, 0x04, 0xE2, 75 | 0x8B, 0xC8, 0x49, 0x97, 0x7F, 0xAC, 0x33, 0xB4, 76 | 0xB5, 0x30, 0xF1, 0xB1, 0x20, 0x24, 0x8A, 0x9A, 77 | } 78 | y := []byte{ 79 | 0x2B, 0xB3, 0x12, 0xA4, 0x3B, 0xD2, 0xCE, 0x6E, 80 | 0x0D, 0x02, 0x06, 0x13, 0xC8, 0x57, 0xAC, 0xDD, 81 | 0xCF, 0xBF, 0x06, 0x1E, 0x91, 0xE5, 0xF2, 0xC3, 82 | 0xF3, 0x24, 0x47, 0xC2, 0x59, 0xF3, 0x9B, 0x2C, 83 | 0x83, 0xAB, 0x15, 0x6D, 0x77, 0xF1, 0x49, 0x6B, 84 | 0xF7, 0xEB, 0x33, 0x51, 0xE1, 0xEE, 0x4E, 0x43, 85 | 0xDC, 0x1A, 0x18, 0xB9, 0x1B, 0x24, 0x64, 0x0B, 86 | 0x6D, 0xBB, 0x92, 0xCB, 0x1A, 0xDD, 0x37, 0x1E, 87 | } 88 | priv := []byte{ 89 | 0xD4, 0x8D, 0xA1, 0x1F, 0x82, 0x67, 0x29, 0xC6, 90 | 0xDF, 0xAA, 0x18, 0xFD, 0x7B, 0x6B, 0x63, 0xA2, 91 | 0x14, 0x27, 0x7E, 0x82, 0xD2, 0xDA, 0x22, 0x33, 92 | 0x56, 0xA0, 0x00, 0x22, 0x3B, 0x12, 0xE8, 0x72, 93 | 0x20, 0x10, 0x8B, 0x50, 0x8E, 0x50, 0xE7, 0x0E, 94 | 0x70, 0x69, 0x46, 0x51, 0xE8, 0xA0, 0x91, 0x30, 95 | 0xC9, 0xD7, 0x56, 0x77, 0xD4, 0x36, 0x09, 0xA4, 96 | 0x1B, 0x24, 0xAE, 0xAD, 0x8A, 0x04, 0xA6, 0x0B, 97 | } 98 | pubX := []byte{ 99 | 0xE1, 0xEF, 0x30, 0xD5, 0x2C, 0x61, 0x33, 0xDD, 100 | 0xD9, 0x9D, 0x1D, 0x5C, 0x41, 0x45, 0x5C, 0xF7, 101 | 0xDF, 0x4D, 0x8B, 0x4C, 0x92, 0x5B, 0xBC, 0x69, 102 | 0xAF, 0x14, 0x33, 0xD1, 0x56, 0x58, 0x51, 0x5A, 103 | 0xDD, 0x21, 0x46, 0x85, 0x0C, 0x32, 0x5C, 0x5B, 104 | 0x81, 0xC1, 0x33, 0xBE, 0x65, 0x5A, 0xA8, 0xC4, 105 | 0xD4, 0x40, 0xE7, 0xB9, 0x8A, 0x8D, 0x59, 0x48, 106 | 0x7B, 0x0C, 0x76, 0x96, 0xBC, 0xC5, 0x5D, 0x11, 107 | } 108 | pubY := []byte{ 109 | 0xEC, 0xBE, 0x77, 0x36, 0xA9, 0xEC, 0x35, 0x7F, 110 | 0xF2, 0xFD, 0x39, 0x93, 0x1F, 0x4E, 0x11, 0x4C, 111 | 0xB8, 0xCD, 0xA3, 0x59, 0x27, 0x0A, 0xC7, 0xF0, 112 | 0xE7, 0xFF, 0x43, 0xD9, 0x41, 0x94, 0x19, 0xEA, 113 | 0x61, 0xFD, 0x2A, 0xB7, 0x7F, 0x5D, 0x9F, 0x63, 114 | 0x52, 0x3D, 0x3B, 0x50, 0xA0, 0x4F, 0x63, 0xE2, 115 | 0xA0, 0xCF, 0x51, 0xB7, 0xC1, 0x3A, 0xDC, 0x21, 116 | 0x56, 0x0F, 0x0B, 0xD4, 0x0C, 0xC9, 0xC7, 0x37, 117 | } 118 | digest := []byte{ 119 | 0x37, 0x54, 0xF3, 0xCF, 0xAC, 0xC9, 0xE0, 0x61, 120 | 0x5C, 0x4F, 0x4A, 0x7C, 0x4D, 0x8D, 0xAB, 0x53, 121 | 0x1B, 0x09, 0xB6, 0xF9, 0xC1, 0x70, 0xC5, 0x33, 122 | 0xA7, 0x1D, 0x14, 0x70, 0x35, 0xB0, 0xC5, 0x91, 123 | 0x71, 0x84, 0xEE, 0x53, 0x65, 0x93, 0xF4, 0x41, 124 | 0x43, 0x39, 0x97, 0x6C, 0x64, 0x7C, 0x5D, 0x5A, 125 | 0x40, 0x7A, 0xDE, 0xDB, 0x1D, 0x56, 0x0C, 0x4F, 126 | 0xC6, 0x77, 0x7D, 0x29, 0x72, 0x07, 0x5B, 0x8C, 127 | } 128 | signature := []byte{ 129 | 0x10, 0x81, 0xB3, 0x94, 0x69, 0x6F, 0xFE, 0x8E, 130 | 0x65, 0x85, 0xE7, 0xA9, 0x36, 0x2D, 0x26, 0xB6, 131 | 0x32, 0x5F, 0x56, 0x77, 0x8A, 0xAD, 0xBC, 0x08, 132 | 0x1C, 0x0B, 0xFB, 0xE9, 0x33, 0xD5, 0x2F, 0xF5, 133 | 0x82, 0x3C, 0xE2, 0x88, 0xE8, 0xC4, 0xF3, 0x62, 134 | 0x52, 0x60, 0x80, 0xDF, 0x7F, 0x70, 0xCE, 0x40, 135 | 0x6A, 0x6E, 0xEB, 0x1F, 0x56, 0x91, 0x9C, 0xB9, 136 | 0x2A, 0x98, 0x53, 0xBD, 0xE7, 0x3E, 0x5B, 0x4A, 137 | 0x2F, 0x86, 0xFA, 0x60, 0xA0, 0x81, 0x09, 0x1A, 138 | 0x23, 0xDD, 0x79, 0x5E, 0x1E, 0x3C, 0x68, 0x9E, 139 | 0xE5, 0x12, 0xA3, 0xC8, 0x2E, 0xE0, 0xDC, 0xC2, 140 | 0x64, 0x3C, 0x78, 0xEE, 0xA8, 0xFC, 0xAC, 0xD3, 141 | 0x54, 0x92, 0x55, 0x84, 0x86, 0xB2, 0x0F, 0x1C, 142 | 0x9E, 0xC1, 0x97, 0xC9, 0x06, 0x99, 0x85, 0x02, 143 | 0x60, 0xC9, 0x3B, 0xCB, 0xCD, 0x9C, 0x5C, 0x33, 144 | 0x17, 0xE1, 0x93, 0x44, 0xE1, 0x73, 0xAE, 0x36, 145 | } 146 | c, err := NewCurve(p, q, a, b, x, y) 147 | if err != nil { 148 | t.FailNow() 149 | } 150 | prv, err := NewPrivateKey(c, Mode2012, priv) 151 | if err != nil { 152 | t.FailNow() 153 | } 154 | pub, err := prv.PublicKey() 155 | if err != nil { 156 | t.FailNow() 157 | } 158 | if bytes.Compare(pub.Raw()[:64], pubX) != 0 { 159 | t.FailNow() 160 | } 161 | if bytes.Compare(pub.Raw()[64:], pubY) != 0 { 162 | t.FailNow() 163 | } 164 | ourSign, err := prv.SignDigest(digest, rand.Reader) 165 | if err != nil { 166 | t.FailNow() 167 | } 168 | valid, err := pub.VerifyDigest(digest, ourSign) 169 | if err != nil || !valid { 170 | t.FailNow() 171 | } 172 | valid, err = pub.VerifyDigest(digest, signature) 173 | if err != nil || !valid { 174 | t.FailNow() 175 | } 176 | } 177 | 178 | func TestRandom2012(t *testing.T) { 179 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 180 | f := func(data [31]byte, digest [64]byte) bool { 181 | prv, err := NewPrivateKey( 182 | c, 183 | Mode2012, 184 | append([]byte{0xde}, data[:]...), 185 | ) 186 | if err != nil { 187 | return false 188 | } 189 | pub, err := prv.PublicKey() 190 | if err != nil { 191 | return false 192 | } 193 | pubRaw := pub.Raw() 194 | pub, err = NewPublicKey(c, Mode2012, pubRaw) 195 | if err != nil { 196 | return false 197 | } 198 | sign, err := prv.SignDigest(digest[:], rand.Reader) 199 | if err != nil { 200 | return false 201 | } 202 | valid, err := pub.VerifyDigest(digest[:], sign) 203 | if err != nil { 204 | return false 205 | } 206 | return valid 207 | } 208 | if err := quick.Check(f, nil); err != nil { 209 | t.Error(err) 210 | } 211 | } 212 | 213 | func BenchmarkSign2012(b *testing.B) { 214 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 215 | prv, err := GenPrivateKey(c, Mode2012, rand.Reader) 216 | if err != nil { 217 | b.FailNow() 218 | } 219 | digest := make([]byte, 64) 220 | rand.Read(digest) 221 | b.ResetTimer() 222 | for i := 0; i < b.N; i++ { 223 | prv.SignDigest(digest, rand.Reader) 224 | } 225 | } 226 | 227 | func BenchmarkVerify2012(b *testing.B) { 228 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 229 | prv, err := GenPrivateKey(c, Mode2012, rand.Reader) 230 | if err != nil { 231 | b.FailNow() 232 | } 233 | digest := make([]byte, 64) 234 | rand.Read(digest) 235 | sign, err := prv.SignDigest(digest, rand.Reader) 236 | if err != nil { 237 | b.FailNow() 238 | } 239 | pub, err := prv.PublicKey() 240 | if err != nil { 241 | b.FailNow() 242 | } 243 | b.ResetTimer() 244 | for i := 0; i < b.N; i++ { 245 | pub.VerifyDigest(digest, sign) 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /gost3410/curve.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "errors" 22 | "math/big" 23 | ) 24 | 25 | var ( 26 | zero *big.Int = big.NewInt(0) 27 | bigInt1 *big.Int = big.NewInt(1) 28 | bigInt2 *big.Int = big.NewInt(2) 29 | bigInt3 *big.Int = big.NewInt(3) 30 | ) 31 | 32 | type Curve struct { 33 | P *big.Int 34 | Q *big.Int 35 | A *big.Int 36 | B *big.Int 37 | 38 | // Basic point X and Y coordinates 39 | Bx *big.Int 40 | By *big.Int 41 | 42 | // Temporary variable for the add method 43 | t *big.Int 44 | tx *big.Int 45 | ty *big.Int 46 | } 47 | 48 | func NewCurve(p, q, a, b, bx, by []byte) (*Curve, error) { 49 | c := Curve{ 50 | P: bytes2big(p[:]), 51 | Q: bytes2big(q[:]), 52 | A: bytes2big(a[:]), 53 | B: bytes2big(b[:]), 54 | Bx: bytes2big(bx[:]), 55 | By: bytes2big(by[:]), 56 | t: big.NewInt(0), 57 | tx: big.NewInt(0), 58 | ty: big.NewInt(0), 59 | } 60 | r1 := big.NewInt(0) 61 | r2 := big.NewInt(0) 62 | r1.Mul(c.By, c.By) 63 | r1.Mod(r1, c.P) 64 | r2.Mul(c.Bx, c.Bx) 65 | r2.Add(r2, c.A) 66 | r2.Mul(r2, c.Bx) 67 | r2.Add(r2, c.B) 68 | r2.Mod(r2, c.P) 69 | if r2.Cmp(big.NewInt(0)) == -1 { 70 | r2.Add(r2, c.P) 71 | } 72 | if r1.Cmp(r2) != 0 { 73 | return nil, errors.New("Invalid curve parameters") 74 | } 75 | return &c, nil 76 | } 77 | 78 | func (c *Curve) pos(v *big.Int) { 79 | if v.Cmp(zero) < 0 { 80 | v.Add(v, c.P) 81 | } 82 | } 83 | 84 | func (c *Curve) add(p1x, p1y, p2x, p2y *big.Int) { 85 | if p1x.Cmp(p2x) == 0 && p1y.Cmp(p2y) == 0 { 86 | // double 87 | c.t.Mul(p1x, p1x) 88 | c.t.Mul(c.t, bigInt3) 89 | c.t.Add(c.t, c.A) 90 | c.tx.Mul(bigInt2, p1y) 91 | c.tx.ModInverse(c.tx, c.P) 92 | c.t.Mul(c.t, c.tx) 93 | c.t.Mod(c.t, c.P) 94 | } else { 95 | c.tx.Sub(p2x, p1x) 96 | c.tx.Mod(c.tx, c.P) 97 | c.pos(c.tx) 98 | c.ty.Sub(p2y, p1y) 99 | c.ty.Mod(c.ty, c.P) 100 | c.pos(c.ty) 101 | c.t.ModInverse(c.tx, c.P) 102 | c.t.Mul(c.t, c.ty) 103 | c.t.Mod(c.t, c.P) 104 | } 105 | c.tx.Mul(c.t, c.t) 106 | c.tx.Sub(c.tx, p1x) 107 | c.tx.Sub(c.tx, p2x) 108 | c.tx.Mod(c.tx, c.P) 109 | c.pos(c.tx) 110 | c.ty.Sub(p1x, c.tx) 111 | c.ty.Mul(c.ty, c.t) 112 | c.ty.Sub(c.ty, p1y) 113 | c.ty.Mod(c.ty, c.P) 114 | c.pos(c.ty) 115 | p1x.Set(c.tx) 116 | p1y.Set(c.ty) 117 | } 118 | 119 | func (c *Curve) Exp(degree, xS, yS *big.Int) (*big.Int, *big.Int, error) { 120 | if degree.Cmp(zero) == 0 { 121 | return nil, nil, errors.New("Bad degree value") 122 | } 123 | dg := big.NewInt(0).Sub(degree, bigInt1) 124 | tx := big.NewInt(0).Set(xS) 125 | ty := big.NewInt(0).Set(yS) 126 | cx := big.NewInt(0).Set(xS) 127 | cy := big.NewInt(0).Set(yS) 128 | for dg.Cmp(zero) != 0 { 129 | if dg.Bit(0) == 1 { 130 | c.add(tx, ty, cx, cy) 131 | } 132 | dg.Rsh(dg, 1) 133 | c.add(cx, cy, cx, cy) 134 | } 135 | return tx, ty, nil 136 | } 137 | -------------------------------------------------------------------------------- /gost3410/doc.go: -------------------------------------------------------------------------------- 1 | // GOST R 34.10-2001 (RFC 5832), 2 | // GOST R 34.10-2012 (RFC 7091) signature algorithms and 3 | // VKO GOST R 34.10-2001 (RFC 4357), 4 | // VKO GOST R 34.10-2012 (RFC 7836) key agreement algorithms. 5 | package gost3410 6 | -------------------------------------------------------------------------------- /gost3410/params.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | type Mode int 21 | 22 | // Curve params: p, q, a, b, bx, by 23 | type CurveParams [6][]byte 24 | 25 | var ( 26 | Mode2001 Mode = Mode(32) 27 | Mode2012 Mode = Mode(64) 28 | 29 | CurveParamsGostR34102001cc CurveParams = CurveParams([6][]byte{ 30 | {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC7}, 34 | {0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 35 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 36 | 0x60, 0x61, 0x17, 0xa2, 0xf4, 0xbd, 0xe4, 0x28, 37 | 0xb7, 0x45, 0x8a, 0x54, 0xb6, 0xe8, 0x7b, 0x85}, 38 | {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc4}, 42 | {0x2d, 0x06, 0xB4, 0x26, 0x5e, 0xbc, 0x74, 0x9f, 43 | 0xf7, 0xd0, 0xf1, 0xf1, 0xf8, 0x82, 0x32, 0xe8, 44 | 0x16, 0x32, 0xe9, 0x08, 0x8f, 0xd4, 0x4b, 0x77, 45 | 0x87, 0xd5, 0xe4, 0x07, 0xe9, 0x55, 0x08, 0x0c}, 46 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 50 | {0xa2, 0x0e, 0x03, 0x4b, 0xf8, 0x81, 0x3e, 0xf5, 51 | 0xc1, 0x8d, 0x01, 0x10, 0x5e, 0x72, 0x6a, 0x17, 52 | 0xeb, 0x24, 0x8b, 0x26, 0x4a, 0xe9, 0x70, 0x6f, 53 | 0x44, 0x0b, 0xed, 0xc8, 0xcc, 0xb6, 0xb2, 0x2c}, 54 | }) 55 | CurveParamsGostR34102001Test CurveParams = CurveParams([6][]byte{ 56 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x31}, 60 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 62 | 0x50, 0xFE, 0x8A, 0x18, 0x92, 0x97, 0x61, 0x54, 63 | 0xC5, 0x9C, 0xFC, 0x19, 0x3A, 0xCC, 0xF5, 0xB3}, 64 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, 68 | {0x5F, 0xBF, 0xF4, 0x98, 0xAA, 0x93, 0x8C, 0xE7, 69 | 0x39, 0xB8, 0xE0, 0x22, 0xFB, 0xAF, 0xEF, 0x40, 70 | 0x56, 0x3F, 0x6E, 0x6A, 0x34, 0x72, 0xFC, 0x2A, 71 | 0x51, 0x4C, 0x0C, 0xE9, 0xDA, 0xE2, 0x3B, 0x7E}, 72 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 76 | {0x08, 0xE2, 0xA8, 0xA0, 0xE6, 0x51, 0x47, 0xD4, 77 | 0xBD, 0x63, 0x16, 0x03, 0x0E, 0x16, 0xD1, 0x9C, 78 | 0x85, 0xC9, 0x7F, 0x0A, 0x9C, 0xA2, 0x67, 0x12, 79 | 0x2B, 0x96, 0xAB, 0xBC, 0xEA, 0x7E, 0x8F, 0xC8}, 80 | }) 81 | CurveParamsGostR34102001CryptoProA CurveParams = CurveParams([6][]byte{ 82 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 83 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 84 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 85 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x97}, 86 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 87 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 88 | 0x6C, 0x61, 0x10, 0x70, 0x99, 0x5A, 0xD1, 0x00, 89 | 0x45, 0x84, 0x1B, 0x09, 0xB7, 0x61, 0xB8, 0x93}, 90 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 91 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 92 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 93 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x94}, 94 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6}, 98 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 102 | {0x8D, 0x91, 0xE4, 0x71, 0xE0, 0x98, 0x9C, 0xDA, 103 | 0x27, 0xDF, 0x50, 0x5A, 0x45, 0x3F, 0x2B, 0x76, 104 | 0x35, 0x29, 0x4F, 0x2D, 0xDF, 0x23, 0xE3, 0xB1, 105 | 0x22, 0xAC, 0xC9, 0x9C, 0x9E, 0x9F, 0x1E, 0x14}, 106 | }) 107 | CurveParamsGostR34102001CryptoProB CurveParams = CurveParams([6][]byte{ 108 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x99}, 112 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 114 | 0x5F, 0x70, 0x0C, 0xFF, 0xF1, 0xA6, 0x24, 0xE5, 115 | 0xE4, 0x97, 0x16, 0x1B, 0xCC, 0x8A, 0x19, 0x8F}, 116 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 118 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 119 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x96}, 120 | {0x3E, 0x1A, 0xF4, 0x19, 0xA2, 0x69, 0xA5, 0xF8, 121 | 0x66, 0xA7, 0xD3, 0xC2, 0x5C, 0x3D, 0xF8, 0x0A, 122 | 0xE9, 0x79, 0x25, 0x93, 0x73, 0xFF, 0x2B, 0x18, 123 | 0x2F, 0x49, 0xD4, 0xCE, 0x7E, 0x1B, 0xBC, 0x8B}, 124 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 128 | {0x3F, 0xA8, 0x12, 0x43, 0x59, 0xF9, 0x66, 0x80, 129 | 0xB8, 0x3D, 0x1C, 0x3E, 0xB2, 0xC0, 0x70, 0xE5, 130 | 0xC5, 0x45, 0xC9, 0x85, 0x8D, 0x03, 0xEC, 0xFB, 131 | 0x74, 0x4B, 0xF8, 0xD7, 0x17, 0x71, 0x7E, 0xFC}, 132 | }) 133 | CurveParamsGostR34102001CryptoProC CurveParams = CurveParams([6][]byte{ 134 | {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07, 135 | 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA, 136 | 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3, 137 | 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x9B}, 138 | {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07, 139 | 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA, 140 | 0x58, 0x2C, 0xA3, 0x51, 0x1E, 0xDD, 0xFB, 0x74, 141 | 0xF0, 0x2F, 0x3A, 0x65, 0x98, 0x98, 0x0B, 0xB9}, 142 | {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07, 143 | 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA, 144 | 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3, 145 | 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x98}, 146 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5a}, 150 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 154 | {0x41, 0xEC, 0xE5, 0x57, 0x43, 0x71, 0x1A, 0x8C, 155 | 0x3C, 0xBF, 0x37, 0x83, 0xCD, 0x08, 0xC0, 0xEE, 156 | 0x4D, 0x4D, 0xC4, 0x40, 0xD4, 0x64, 0x1A, 0x8F, 157 | 0x36, 0x6E, 0x55, 0x0D, 0xFD, 0xB3, 0xBB, 0x67}, 158 | }) 159 | CurveParamsGostR34102001CryptoProXchA CurveParams = CurveParams([6][]byte{ 160 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 161 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 162 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 163 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x97}, 164 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 165 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 166 | 0x6C, 0x61, 0x10, 0x70, 0x99, 0x5A, 0xD1, 0x00, 167 | 0x45, 0x84, 0x1B, 0x09, 0xB7, 0x61, 0xB8, 0x93}, 168 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 169 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 170 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 171 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x94}, 172 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6}, 176 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 180 | {0x8D, 0x91, 0xE4, 0x71, 0xE0, 0x98, 0x9C, 0xDA, 181 | 0x27, 0xDF, 0x50, 0x5A, 0x45, 0x3F, 0x2B, 0x76, 182 | 0x35, 0x29, 0x4F, 0x2D, 0xDF, 0x23, 0xE3, 0xB1, 183 | 0x22, 0xAC, 0xC9, 0x9C, 0x9E, 0x9F, 0x1E, 0x14}, 184 | }) 185 | CurveParamsGostR34102001CryptoProXchB CurveParams = CurveParams([6][]byte{ 186 | {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07, 187 | 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA, 188 | 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3, 189 | 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x9B}, 190 | {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07, 191 | 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA, 192 | 0x58, 0x2C, 0xA3, 0x51, 0x1E, 0xDD, 0xFB, 0x74, 193 | 0xF0, 0x2F, 0x3A, 0x65, 0x98, 0x98, 0x0B, 0xB9}, 194 | {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07, 195 | 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA, 196 | 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3, 197 | 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x98}, 198 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5a}, 202 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 206 | {0x41, 0xEC, 0xE5, 0x57, 0x43, 0x71, 0x1A, 0x8C, 207 | 0x3C, 0xBF, 0x37, 0x83, 0xCD, 0x08, 0xC0, 0xEE, 208 | 0x4D, 0x4D, 0xC4, 0x40, 0xD4, 0x64, 0x1A, 0x8F, 209 | 0x36, 0x6E, 0x55, 0x0D, 0xFD, 0xB3, 0xBB, 0x67}, 210 | }) 211 | CurveParamsGostR34102012TC26ParamSetA CurveParams = CurveParams([6][]byte{ 212 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 213 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 214 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 215 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 216 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 217 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 218 | 0xFF, 0xFF, 0xFD, 0xC7}, 219 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 220 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 221 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 222 | 0xFF, 0xFF, 0x27, 0xE6, 0x95, 0x32, 0xF4, 0x8D, 0x89, 0x11, 223 | 0x6F, 0xF2, 0x2B, 0x8D, 0x4E, 0x05, 0x60, 0x60, 0x9B, 0x4B, 224 | 0x38, 0xAB, 0xFA, 0xD2, 0xB8, 0x5D, 0xCA, 0xCD, 0xB1, 0x41, 225 | 0x1F, 0x10, 0xB2, 0x75}, 226 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 227 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 228 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 229 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 230 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 231 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 232 | 0xFF, 0xFF, 0xFD, 0xC4}, 233 | {0xE8, 0xC2, 0x50, 0x5D, 0xED, 0xFC, 0x86, 0xDD, 0xC1, 0xBD, 234 | 0x0B, 0x2B, 0x66, 0x67, 0xF1, 0xDA, 0x34, 0xB8, 0x25, 0x74, 235 | 0x76, 0x1C, 0xB0, 0xE8, 0x79, 0xBD, 0x08, 0x1C, 0xFD, 0x0B, 236 | 0x62, 0x65, 0xEE, 0x3C, 0xB0, 0x90, 0xF3, 0x0D, 0x27, 0x61, 237 | 0x4C, 0xB4, 0x57, 0x40, 0x10, 0xDA, 0x90, 0xDD, 0x86, 0x2E, 238 | 0xF9, 0xD4, 0xEB, 0xEE, 0x47, 0x61, 0x50, 0x31, 0x90, 0x78, 239 | 0x5A, 0x71, 0xC7, 0x60}, 240 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 241 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 242 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 243 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 246 | 0x00, 0x00, 0x00, 0x03}, 247 | {0x75, 0x03, 0xCF, 0xE8, 0x7A, 0x83, 0x6A, 0xE3, 0xA6, 0x1B, 248 | 0x88, 0x16, 0xE2, 0x54, 0x50, 0xE6, 0xCE, 0x5E, 0x1C, 0x93, 249 | 0xAC, 0xF1, 0xAB, 0xC1, 0x77, 0x80, 0x64, 0xFD, 0xCB, 0xEF, 250 | 0xA9, 0x21, 0xDF, 0x16, 0x26, 0xBE, 0x4F, 0xD0, 0x36, 0xE9, 251 | 0x3D, 0x75, 0xE6, 0xA5, 0x0E, 0x3A, 0x41, 0xE9, 0x80, 0x28, 252 | 0xFE, 0x5F, 0xC2, 0x35, 0xF5, 0xB8, 0x89, 0xA5, 0x89, 0xCB, 253 | 0x52, 0x15, 0xF2, 0xA4}, 254 | }) 255 | CurveParamsGostR34102012TC26ParamSetB CurveParams = CurveParams([6][]byte{ 256 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 257 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 258 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 259 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 260 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 261 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 262 | 0x00, 0x00, 0x00, 0x6F}, 263 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 264 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 266 | 0x00, 0x01, 0x49, 0xA1, 0xEC, 0x14, 0x25, 0x65, 0xA5, 0x45, 267 | 0xAC, 0xFD, 0xB7, 0x7B, 0xD9, 0xD4, 0x0C, 0xFA, 0x8B, 0x99, 268 | 0x67, 0x12, 0x10, 0x1B, 0xEA, 0x0E, 0xC6, 0x34, 0x6C, 0x54, 269 | 0x37, 0x4F, 0x25, 0xBD}, 270 | {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 271 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 272 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 274 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 275 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 276 | 0x00, 0x00, 0x00, 0x6C}, 277 | {0x68, 0x7D, 0x1B, 0x45, 0x9D, 0xC8, 0x41, 0x45, 0x7E, 0x3E, 278 | 0x06, 0xCF, 0x6F, 0x5E, 0x25, 0x17, 0xB9, 0x7C, 0x7D, 0x61, 279 | 0x4A, 0xF1, 0x38, 0xBC, 0xBF, 0x85, 0xDC, 0x80, 0x6C, 0x4B, 280 | 0x28, 0x9F, 0x3E, 0x96, 0x5D, 0x2D, 0xB1, 0x41, 0x6D, 0x21, 281 | 0x7F, 0x8B, 0x27, 0x6F, 0xAD, 0x1A, 0xB6, 0x9C, 0x50, 0xF7, 282 | 0x8B, 0xEE, 0x1F, 0xA3, 0x10, 0x6E, 0xFB, 0x8C, 0xCB, 0xC7, 283 | 0xC5, 0x14, 0x01, 0x16}, 284 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 285 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 286 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 287 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 288 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 289 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 290 | 0x00, 0x00, 0x00, 0x02}, 291 | {0x1A, 0x8F, 0x7E, 0xDA, 0x38, 0x9B, 0x09, 0x4C, 0x2C, 0x07, 292 | 0x1E, 0x36, 0x47, 0xA8, 0x94, 0x0F, 0x3C, 0x12, 0x3B, 0x69, 293 | 0x75, 0x78, 0xC2, 0x13, 0xBE, 0x6D, 0xD9, 0xE6, 0xC8, 0xEC, 294 | 0x73, 0x35, 0xDC, 0xB2, 0x28, 0xFD, 0x1E, 0xDF, 0x4A, 0x39, 295 | 0x15, 0x2C, 0xBC, 0xAA, 0xF8, 0xC0, 0x39, 0x88, 0x28, 0x04, 296 | 0x10, 0x55, 0xF9, 0x4C, 0xEE, 0xEC, 0x7E, 0x21, 0x34, 0x07, 297 | 0x80, 0xFE, 0x41, 0xBD}, 298 | }) 299 | 300 | CurveParamsDefault = CurveParamsGostR34102001CryptoProA 301 | ) 302 | 303 | func NewCurveFromParams(params CurveParams) (*Curve, error) { 304 | return NewCurve( 305 | params[0][:], 306 | params[1][:], 307 | params[2][:], 308 | params[3][:], 309 | params[4][:], 310 | params[5][:], 311 | ) 312 | } 313 | -------------------------------------------------------------------------------- /gost3410/private.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "errors" 22 | "io" 23 | "math/big" 24 | ) 25 | 26 | type PrivateKey struct { 27 | c *Curve 28 | mode Mode 29 | key *big.Int 30 | } 31 | 32 | func NewPrivateKey(curve *Curve, mode Mode, raw []byte) (*PrivateKey, error) { 33 | if len(raw) != int(mode) { 34 | errors.New("Invalid private key length") 35 | } 36 | key := make([]byte, int(mode)) 37 | copy(key, raw) 38 | reverse(key) 39 | k := bytes2big(key) 40 | if k.Cmp(zero) == 0 { 41 | return nil, errors.New("Zero private key") 42 | } 43 | return &PrivateKey{curve, mode, k}, nil 44 | } 45 | 46 | func GenPrivateKey(curve *Curve, mode Mode, rand io.Reader) (*PrivateKey, error) { 47 | raw := make([]byte, int(mode)) 48 | if _, err := io.ReadFull(rand, raw); err != nil { 49 | return nil, err 50 | } 51 | return NewPrivateKey(curve, mode, raw) 52 | } 53 | 54 | func (prv *PrivateKey) Raw() []byte { 55 | raw := pad(prv.key.Bytes(), int(prv.mode)) 56 | reverse(raw) 57 | return raw 58 | } 59 | 60 | func (prv *PrivateKey) PublicKey() (*PublicKey, error) { 61 | x, y, err := prv.c.Exp(prv.key, prv.c.Bx, prv.c.By) 62 | if err != nil { 63 | return nil, err 64 | } 65 | return &PublicKey{prv.c, prv.mode, x, y}, nil 66 | } 67 | 68 | func (prv *PrivateKey) SignDigest(digest []byte, rand io.Reader) ([]byte, error) { 69 | e := bytes2big(digest) 70 | e.Mod(e, prv.c.Q) 71 | if e.Cmp(zero) == 0 { 72 | e = big.NewInt(1) 73 | } 74 | kRaw := make([]byte, int(prv.mode)) 75 | var err error 76 | var k *big.Int 77 | var r *big.Int 78 | d := big.NewInt(0) 79 | s := big.NewInt(0) 80 | Retry: 81 | if _, err = io.ReadFull(rand, kRaw); err != nil { 82 | return nil, err 83 | } 84 | k = bytes2big(kRaw) 85 | k.Mod(k, prv.c.Q) 86 | if k.Cmp(zero) == 0 { 87 | goto Retry 88 | } 89 | r, _, err = prv.c.Exp(k, prv.c.Bx, prv.c.By) 90 | if err != nil { 91 | return nil, err 92 | } 93 | r.Mod(r, prv.c.Q) 94 | if r.Cmp(zero) == 0 { 95 | goto Retry 96 | } 97 | d.Mul(prv.key, r) 98 | k.Mul(k, e) 99 | s.Add(d, k) 100 | s.Mod(s, prv.c.Q) 101 | if s.Cmp(zero) == 0 { 102 | goto Retry 103 | } 104 | return append( 105 | pad(s.Bytes(), int(prv.mode)), 106 | pad(r.Bytes(), int(prv.mode))..., 107 | ), nil 108 | } 109 | -------------------------------------------------------------------------------- /gost3410/public.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "errors" 22 | "math/big" 23 | ) 24 | 25 | type PublicKey struct { 26 | c *Curve 27 | mode Mode 28 | x *big.Int 29 | y *big.Int 30 | } 31 | 32 | func NewPublicKey(curve *Curve, mode Mode, raw []byte) (*PublicKey, error) { 33 | if len(raw) != 2*int(mode) { 34 | return nil, errors.New("Invalid public key length") 35 | } 36 | key := make([]byte, 2*int(mode)) 37 | copy(key, raw) 38 | reverse(key) 39 | return &PublicKey{ 40 | curve, 41 | mode, 42 | bytes2big(key[int(mode) : 2*int(mode)]), 43 | bytes2big(key[:int(mode)]), 44 | }, nil 45 | } 46 | 47 | func (pub *PublicKey) Raw() []byte { 48 | raw := append( 49 | pad(pub.y.Bytes(), int(pub.mode)), 50 | pad(pub.x.Bytes(), int(pub.mode))..., 51 | ) 52 | reverse(raw) 53 | return raw 54 | } 55 | 56 | func (pub *PublicKey) VerifyDigest(digest, signature []byte) (bool, error) { 57 | if len(signature) != 2*int(pub.mode) { 58 | return false, errors.New("Invalid signature length") 59 | } 60 | s := bytes2big(signature[:pub.mode]) 61 | r := bytes2big(signature[pub.mode:]) 62 | if r.Cmp(zero) <= 0 || r.Cmp(pub.c.Q) >= 0 || s.Cmp(zero) <= 0 || s.Cmp(pub.c.Q) >= 0 { 63 | return false, nil 64 | } 65 | e := bytes2big(digest) 66 | e.Mod(e, pub.c.Q) 67 | if e.Cmp(zero) == 0 { 68 | e = big.NewInt(1) 69 | } 70 | v := big.NewInt(0) 71 | v.ModInverse(e, pub.c.Q) 72 | z1 := big.NewInt(0) 73 | z2 := big.NewInt(0) 74 | z1.Mul(s, v) 75 | z1.Mod(z1, pub.c.Q) 76 | z2.Mul(r, v) 77 | z2.Mod(z2, pub.c.Q) 78 | z2.Sub(pub.c.Q, z2) 79 | p1x, p1y, err := pub.c.Exp(z1, pub.c.Bx, pub.c.By) 80 | if err != nil { 81 | return false, err 82 | } 83 | q1x, q1y, err := pub.c.Exp(z2, pub.x, pub.y) 84 | if err != nil { 85 | return false, err 86 | } 87 | lm := big.NewInt(0) 88 | lm.Sub(q1x, p1x) 89 | if lm.Cmp(zero) < 0 { 90 | lm.Add(lm, pub.c.P) 91 | } 92 | lm.ModInverse(lm, pub.c.P) 93 | z1.Sub(q1y, p1y) 94 | lm.Mul(lm, z1) 95 | lm.Mod(lm, pub.c.P) 96 | lm.Mul(lm, lm) 97 | lm.Mod(lm, pub.c.P) 98 | lm.Sub(lm, p1x) 99 | lm.Sub(lm, q1x) 100 | lm.Mod(lm, pub.c.P) 101 | if lm.Cmp(zero) < 0 { 102 | lm.Add(lm, pub.c.P) 103 | } 104 | lm.Mod(lm, pub.c.Q) 105 | return lm.Cmp(r) == 0, nil 106 | } 107 | -------------------------------------------------------------------------------- /gost3410/ukm.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "math/big" 22 | ) 23 | 24 | func NewUKM(raw []byte) *big.Int { 25 | t := make([]byte, len(raw)) 26 | copy(t, raw) 27 | reverse(t) 28 | return bytes2big(t) 29 | } 30 | -------------------------------------------------------------------------------- /gost3410/utils.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "math/big" 22 | ) 23 | 24 | func bytes2big(d []byte) *big.Int { 25 | n := big.NewInt(0) 26 | n.SetBytes(d) 27 | return n 28 | } 29 | 30 | func reverse(d []byte) { 31 | for i, j := 0, len(d)-1; i < j; i, j = i+1, j-1 { 32 | d[i], d[j] = d[j], d[i] 33 | } 34 | } 35 | 36 | func pad(d []byte, size int) []byte { 37 | return append(make([]byte, size-len(d)), d...) 38 | } 39 | -------------------------------------------------------------------------------- /gost3410/vko.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "math/big" 22 | ) 23 | 24 | func (prv *PrivateKey) KEK(pub *PublicKey, ukm *big.Int) ([]byte, error) { 25 | keyX, keyY, err := prv.c.Exp(prv.key, pub.x, pub.y) 26 | if err != nil { 27 | return nil, err 28 | } 29 | keyX, keyY, err = prv.c.Exp(ukm, keyX, keyY) 30 | if err != nil { 31 | return nil, err 32 | } 33 | pk := PublicKey{prv.c, prv.mode, keyX, keyY} 34 | return pk.Raw(), nil 35 | } 36 | -------------------------------------------------------------------------------- /gost3410/vko2001.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "errors" 22 | "math/big" 23 | 24 | "github.com/martinlindhe/gogost/gost28147" 25 | "github.com/martinlindhe/gogost/gost341194" 26 | ) 27 | 28 | // RFC 4357 VKO GOST R 34.10-2001 key agreement function. 29 | // UKM is user keying material, also called VKO-factor. 30 | func (prv *PrivateKey) KEK2001(pub *PublicKey, ukm *big.Int) ([]byte, error) { 31 | if prv.mode != Mode2001 { 32 | return nil, errors.New("KEK2001 can not be used in Mode2012") 33 | } 34 | key, err := prv.KEK(pub, ukm) 35 | if err != nil { 36 | return nil, err 37 | } 38 | h := gost341194.New(&gost28147.GostR3411_94_CryptoProParamSet) 39 | h.Write(key) 40 | return h.Sum(key[:0]), nil 41 | } 42 | -------------------------------------------------------------------------------- /gost3410/vko2001_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "bytes" 22 | "encoding/hex" 23 | "testing" 24 | "testing/quick" 25 | ) 26 | 27 | func TestVKO2001(t *testing.T) { 28 | c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) 29 | ukmRaw, _ := hex.DecodeString("5172be25f852a233") 30 | ukm := NewUKM(ukmRaw) 31 | prvRaw1, _ := hex.DecodeString("1df129e43dab345b68f6a852f4162dc69f36b2f84717d08755cc5c44150bf928") 32 | prvRaw2, _ := hex.DecodeString("5b9356c6474f913f1e83885ea0edd5df1a43fd9d799d219093241157ac9ed473") 33 | kek, _ := hex.DecodeString("ee4618a0dbb10cb31777b4b86a53d9e7ef6cb3e400101410f0c0f2af46c494a6") 34 | prv1, _ := NewPrivateKey(c, Mode2001, prvRaw1) 35 | prv2, _ := NewPrivateKey(c, Mode2001, prvRaw2) 36 | pub1, _ := prv1.PublicKey() 37 | pub2, _ := prv2.PublicKey() 38 | kek1, _ := prv1.KEK2001(pub2, ukm) 39 | kek2, _ := prv2.KEK2001(pub1, ukm) 40 | if bytes.Compare(kek1, kek2) != 0 { 41 | t.FailNow() 42 | } 43 | if bytes.Compare(kek1, kek) != 0 { 44 | t.FailNow() 45 | } 46 | } 47 | 48 | func TestRandomVKO2001(t *testing.T) { 49 | c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) 50 | f := func(prvRaw1 [32]byte, prvRaw2 [32]byte, ukmRaw [8]byte) bool { 51 | prv1, err := NewPrivateKey(c, Mode2001, prvRaw1[:]) 52 | if err != nil { 53 | return false 54 | } 55 | prv2, err := NewPrivateKey(c, Mode2001, prvRaw2[:]) 56 | if err != nil { 57 | return false 58 | } 59 | pub1, _ := prv1.PublicKey() 60 | pub2, _ := prv2.PublicKey() 61 | ukm := NewUKM(ukmRaw[:]) 62 | kek1, _ := prv1.KEK2001(pub2, ukm) 63 | kek2, _ := prv2.KEK2001(pub1, ukm) 64 | return bytes.Compare(kek1, kek2) == 0 65 | } 66 | if err := quick.Check(f, nil); err != nil { 67 | t.Error(err) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /gost3410/vko2012.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "errors" 22 | "math/big" 23 | 24 | "github.com/martinlindhe/gogost/gost34112012256" 25 | "github.com/martinlindhe/gogost/gost34112012512" 26 | ) 27 | 28 | // RFC 7836 VKO GOST R 34.10-2012 256-bit key agreement function. 29 | // UKM is user keying material, also called VKO-factor. 30 | func (prv *PrivateKey) KEK2012256(pub *PublicKey, ukm *big.Int) ([]byte, error) { 31 | if prv.mode != Mode2012 { 32 | return nil, errors.New("KEK2012 can not be used in Mode2001") 33 | } 34 | key, err := prv.KEK(pub, ukm) 35 | if err != nil { 36 | return nil, err 37 | } 38 | h := gost34112012256.New() 39 | h.Write(key) 40 | return h.Sum(key[:0]), nil 41 | } 42 | 43 | // RFC 7836 VKO GOST R 34.10-2012 512-bit key agreement function. 44 | // UKM is user keying material, also called VKO-factor. 45 | func (prv *PrivateKey) KEK2012512(pub *PublicKey, ukm *big.Int) ([]byte, error) { 46 | if prv.mode != Mode2012 { 47 | return nil, errors.New("KEK2012 can not be used in Mode2001") 48 | } 49 | key, err := prv.KEK(pub, ukm) 50 | if err != nil { 51 | return nil, err 52 | } 53 | h := gost34112012512.New() 54 | h.Write(key) 55 | return h.Sum(key[:0]), nil 56 | } 57 | -------------------------------------------------------------------------------- /gost3410/vko2012_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3410 19 | 20 | import ( 21 | "bytes" 22 | "encoding/hex" 23 | "testing" 24 | "testing/quick" 25 | ) 26 | 27 | func TestVKO2012256(t *testing.T) { 28 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 29 | ukmRaw, _ := hex.DecodeString("1d80603c8544c727") 30 | ukm := NewUKM(ukmRaw) 31 | prvRawA, _ := hex.DecodeString("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667") 32 | pubRawA, _ := hex.DecodeString("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a") 33 | prvRawB, _ := hex.DecodeString("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db") 34 | pubRawB, _ := hex.DecodeString("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79") 35 | pubA, _ := NewPublicKey(c, Mode2012, pubRawA) 36 | pubB, _ := NewPublicKey(c, Mode2012, pubRawB) 37 | kek, _ := hex.DecodeString("c9a9a77320e2cc559ed72dce6f47e2192ccea95fa648670582c054c0ef36c221") 38 | prvA, _ := NewPrivateKey(c, Mode2012, prvRawA) 39 | prvB, _ := NewPrivateKey(c, Mode2012, prvRawB) 40 | kekA, _ := prvA.KEK2012256(pubB, ukm) 41 | kekB, _ := prvB.KEK2012256(pubA, ukm) 42 | if bytes.Compare(kekA, kekB) != 0 { 43 | t.FailNow() 44 | } 45 | if bytes.Compare(kekA, kek) != 0 { 46 | t.FailNow() 47 | } 48 | } 49 | 50 | func TestRandomVKO2012256(t *testing.T) { 51 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 52 | f := func(prvRaw1 [64]byte, prvRaw2 [64]byte, ukmRaw [8]byte) bool { 53 | prv1, err := NewPrivateKey(c, Mode2012, prvRaw1[:]) 54 | if err != nil { 55 | return false 56 | } 57 | prv2, err := NewPrivateKey(c, Mode2012, prvRaw2[:]) 58 | if err != nil { 59 | return false 60 | } 61 | pub1, _ := prv1.PublicKey() 62 | pub2, _ := prv2.PublicKey() 63 | ukm := NewUKM(ukmRaw[:]) 64 | kek1, _ := prv1.KEK2012256(pub2, ukm) 65 | kek2, _ := prv2.KEK2012256(pub1, ukm) 66 | return bytes.Compare(kek1, kek2) == 0 67 | } 68 | if err := quick.Check(f, nil); err != nil { 69 | t.Error(err) 70 | } 71 | } 72 | 73 | func TestVKO2012512(t *testing.T) { 74 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 75 | ukmRaw, _ := hex.DecodeString("1d80603c8544c727") 76 | ukm := NewUKM(ukmRaw) 77 | prvRawA, _ := hex.DecodeString("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667") 78 | pubRawA, _ := hex.DecodeString("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a") 79 | prvRawB, _ := hex.DecodeString("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db") 80 | pubRawB, _ := hex.DecodeString("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79") 81 | pubA, _ := NewPublicKey(c, Mode2012, pubRawA) 82 | pubB, _ := NewPublicKey(c, Mode2012, pubRawB) 83 | kek, _ := hex.DecodeString("79f002a96940ce7bde3259a52e015297adaad84597a0d205b50e3e1719f97bfa7ee1d2661fa9979a5aa235b558a7e6d9f88f982dd63fc35a8ec0dd5e242d3bdf") 84 | prvA, _ := NewPrivateKey(c, Mode2012, prvRawA) 85 | prvB, _ := NewPrivateKey(c, Mode2012, prvRawB) 86 | kekA, _ := prvA.KEK2012512(pubB, ukm) 87 | kekB, _ := prvB.KEK2012512(pubA, ukm) 88 | if bytes.Compare(kekA, kekB) != 0 { 89 | t.FailNow() 90 | } 91 | if bytes.Compare(kekA, kek) != 0 { 92 | t.FailNow() 93 | } 94 | } 95 | 96 | func TestRandomVKO2012512(t *testing.T) { 97 | c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) 98 | f := func(prvRaw1 [64]byte, prvRaw2 [64]byte, ukmRaw [8]byte) bool { 99 | prv1, err := NewPrivateKey(c, Mode2012, prvRaw1[:]) 100 | if err != nil { 101 | return false 102 | } 103 | prv2, err := NewPrivateKey(c, Mode2012, prvRaw2[:]) 104 | if err != nil { 105 | return false 106 | } 107 | pub1, _ := prv1.PublicKey() 108 | pub2, _ := prv2.PublicKey() 109 | ukm := NewUKM(ukmRaw[:]) 110 | kek1, _ := prv1.KEK2012512(pub2, ukm) 111 | kek2, _ := prv2.KEK2012512(pub1, ukm) 112 | return bytes.Compare(kek1, kek2) == 0 113 | } 114 | if err := quick.Check(f, nil); err != nil { 115 | t.Error(err) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /gost34112012256/hash.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST R 34.11-2012 256-bit hash function. 19 | // RFC 6986. 20 | package gost34112012256 21 | 22 | import ( 23 | "github.com/martinlindhe/gogost/internal/gost34112012" 24 | ) 25 | 26 | const ( 27 | BlockSize = gost34112012.BlockSize 28 | Size = 32 29 | ) 30 | 31 | func New() *gost34112012.Hash { 32 | return gost34112012.New(32) 33 | } 34 | -------------------------------------------------------------------------------- /gost34112012512/hash.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST R 34.11-2012 512-bit hash function. 19 | // RFC 6986. 20 | package gost34112012512 21 | 22 | import ( 23 | "github.com/martinlindhe/gogost/internal/gost34112012" 24 | ) 25 | 26 | const ( 27 | BlockSize = gost34112012.BlockSize 28 | Size = 64 29 | ) 30 | 31 | func New() *gost34112012.Hash { 32 | return gost34112012.New(64) 33 | } 34 | -------------------------------------------------------------------------------- /gost341194/hash.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST R 34.11-94 hash function. 19 | // RFC 5831. 20 | package gost341194 21 | 22 | import ( 23 | "encoding/binary" 24 | "math/big" 25 | 26 | "github.com/martinlindhe/gogost/gost28147" 27 | ) 28 | 29 | const ( 30 | BlockSize = 32 31 | Size = 32 32 | ) 33 | 34 | var ( 35 | SboxDefault *gost28147.Sbox = &gost28147.GostR3411_94_TestParamSet 36 | 37 | c2 [BlockSize]byte = [BlockSize]byte{ 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | } 43 | c3 [BlockSize]byte = [BlockSize]byte{ 44 | 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 45 | 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 46 | 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 47 | 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 48 | } 49 | c4 [BlockSize]byte = [BlockSize]byte{ 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 | } 55 | 56 | big256 *big.Int = big.NewInt(0).SetBit(big.NewInt(0), 256, 1) 57 | ) 58 | 59 | type Hash struct { 60 | sbox *gost28147.Sbox 61 | size uint64 62 | hsh [BlockSize]byte 63 | chk *big.Int 64 | buf []byte 65 | tmp [BlockSize]byte 66 | } 67 | 68 | func New(sbox *gost28147.Sbox) *Hash { 69 | h := Hash{sbox: sbox} 70 | h.Reset() 71 | return &h 72 | } 73 | 74 | func (h *Hash) Reset() { 75 | h.size = 0 76 | h.hsh = [BlockSize]byte{ 77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | } 82 | h.chk = big.NewInt(0) 83 | h.buf = h.buf[:0] 84 | } 85 | 86 | func (h *Hash) BlockSize() int { 87 | return BlockSize 88 | } 89 | 90 | func (h *Hash) Size() int { 91 | return BlockSize 92 | } 93 | 94 | func fA(in *[BlockSize]byte) *[BlockSize]byte { 95 | out := new([BlockSize]byte) 96 | out[0] = in[16+0] ^ in[24+0] 97 | out[1] = in[16+1] ^ in[24+1] 98 | out[2] = in[16+2] ^ in[24+2] 99 | out[3] = in[16+3] ^ in[24+3] 100 | out[4] = in[16+4] ^ in[24+4] 101 | out[5] = in[16+5] ^ in[24+5] 102 | out[6] = in[16+6] ^ in[24+6] 103 | out[7] = in[16+7] ^ in[24+7] 104 | copy(out[8:], in[0:24]) 105 | return out 106 | } 107 | 108 | func fP(in *[BlockSize]byte) *[BlockSize]byte { 109 | return &[BlockSize]byte{ 110 | in[0], in[8], in[16], in[24], in[1], in[9], in[17], 111 | in[25], in[2], in[10], in[18], in[26], in[3], 112 | in[11], in[19], in[27], in[4], in[12], in[20], 113 | in[28], in[5], in[13], in[21], in[29], in[6], 114 | in[14], in[22], in[30], in[7], in[15], in[23], in[31], 115 | } 116 | } 117 | 118 | func fChi(in *[BlockSize]byte) *[BlockSize]byte { 119 | out := new([BlockSize]byte) 120 | out[0] = in[32-2] ^ in[32-4] ^ in[32-6] ^ in[32-8] ^ in[32-32] ^ in[32-26] 121 | out[1] = in[32-1] ^ in[32-3] ^ in[32-5] ^ in[32-7] ^ in[32-31] ^ in[32-25] 122 | copy(out[2:32], in[0:30]) 123 | return out 124 | } 125 | 126 | func blockReverse(dst, src []byte) { 127 | for i, j := 0, BlockSize-1; i < j; i, j = i+1, j-1 { 128 | dst[i], dst[j] = src[j], src[i] 129 | } 130 | } 131 | 132 | func blockXor(dst, a, b *[BlockSize]byte) { 133 | for i := 0; i < BlockSize; i++ { 134 | dst[i] = a[i] ^ b[i] 135 | } 136 | return 137 | } 138 | 139 | func (h *Hash) step(hin, m [BlockSize]byte) [BlockSize]byte { 140 | out := new([BlockSize]byte) 141 | u := new([BlockSize]byte) 142 | v := new([BlockSize]byte) 143 | k := new([BlockSize]byte) 144 | (*u) = hin 145 | (*v) = m 146 | blockXor(k, u, v) 147 | k = fP(k) 148 | blockReverse(k[:], k[:]) 149 | kk := *k 150 | c := gost28147.NewCipher(kk, h.sbox) 151 | s := make([]byte, gost28147.BlockSize) 152 | c.Encrypt(s, []byte{ 153 | hin[31], hin[30], hin[29], hin[28], hin[27], hin[26], hin[25], hin[24], 154 | }) 155 | out[31] = s[0] 156 | out[30] = s[1] 157 | out[29] = s[2] 158 | out[28] = s[3] 159 | out[27] = s[4] 160 | out[26] = s[5] 161 | out[25] = s[6] 162 | out[24] = s[7] 163 | 164 | blockXor(u, fA(u), &c2) 165 | v = fA(fA(v)) 166 | blockXor(k, u, v) 167 | k = fP(k) 168 | blockReverse(k[:], k[:]) 169 | c = gost28147.NewCipher(*k, h.sbox) 170 | c.Encrypt(s, []byte{ 171 | hin[23], hin[22], hin[21], hin[20], hin[19], hin[18], hin[17], hin[16], 172 | }) 173 | out[23] = s[0] 174 | out[22] = s[1] 175 | out[21] = s[2] 176 | out[20] = s[3] 177 | out[19] = s[4] 178 | out[18] = s[5] 179 | out[17] = s[6] 180 | out[16] = s[7] 181 | 182 | blockXor(u, fA(u), &c3) 183 | v = fA(fA(v)) 184 | blockXor(k, u, v) 185 | k = fP(k) 186 | blockReverse(k[:], k[:]) 187 | c = gost28147.NewCipher(*k, h.sbox) 188 | c.Encrypt(s, []byte{ 189 | hin[15], hin[14], hin[13], hin[12], hin[11], hin[10], hin[9], hin[8], 190 | }) 191 | out[15] = s[0] 192 | out[14] = s[1] 193 | out[13] = s[2] 194 | out[12] = s[3] 195 | out[11] = s[4] 196 | out[10] = s[5] 197 | out[9] = s[6] 198 | out[8] = s[7] 199 | 200 | blockXor(u, fA(u), &c4) 201 | v = fA(fA(v)) 202 | blockXor(k, u, v) 203 | k = fP(k) 204 | blockReverse(k[:], k[:]) 205 | c = gost28147.NewCipher(*k, h.sbox) 206 | c.Encrypt(s, []byte{ 207 | hin[7], hin[6], hin[5], hin[4], hin[3], hin[2], hin[1], hin[0], 208 | }) 209 | out[7] = s[0] 210 | out[6] = s[1] 211 | out[5] = s[2] 212 | out[4] = s[3] 213 | out[3] = s[4] 214 | out[2] = s[5] 215 | out[1] = s[6] 216 | out[0] = s[7] 217 | 218 | for i := 0; i < 12; i++ { 219 | out = fChi(out) 220 | } 221 | blockXor(out, out, &m) 222 | out = fChi(out) 223 | blockXor(out, out, &hin) 224 | for i := 0; i < 61; i++ { 225 | out = fChi(out) 226 | } 227 | return *out 228 | } 229 | 230 | func (h *Hash) chkAdd(data []byte) *big.Int { 231 | i := big.NewInt(0).SetBytes(data) 232 | i.Add(i, h.chk) 233 | if i.Cmp(big256) != -1 { 234 | i.Sub(i, big256) 235 | } 236 | return i 237 | } 238 | 239 | func (h *Hash) Write(data []byte) (int, error) { 240 | h.buf = append(h.buf, data...) 241 | for len(h.buf) >= BlockSize { 242 | h.size += BlockSize * 8 243 | blockReverse(h.tmp[:], h.buf[:BlockSize]) 244 | h.chk = h.chkAdd(h.tmp[:]) 245 | h.buf = h.buf[BlockSize:] 246 | h.hsh = h.step(h.hsh, h.tmp) 247 | } 248 | return len(data), nil 249 | } 250 | 251 | func (h *Hash) Sum(in []byte) []byte { 252 | size := h.size 253 | chk := h.chk 254 | hsh := h.hsh 255 | block := new([BlockSize]byte) 256 | if len(h.buf) != 0 { 257 | size += uint64(len(h.buf)) * 8 258 | copy(block[:], h.buf) 259 | blockReverse(block[:], block[:]) 260 | chk = h.chkAdd(block[:]) 261 | hsh = h.step(hsh, *block) 262 | block = new([BlockSize]byte) 263 | } 264 | binary.BigEndian.PutUint64(block[24:], size) 265 | hsh = h.step(hsh, *block) 266 | block = new([BlockSize]byte) 267 | chkBytes := chk.Bytes() 268 | copy(block[BlockSize-len(chkBytes):], chkBytes) 269 | hsh = h.step(hsh, *block) 270 | blockReverse(hsh[:], hsh[:]) 271 | return append(in, hsh[:]...) 272 | } 273 | -------------------------------------------------------------------------------- /gost341194/hash_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost341194 19 | 20 | import ( 21 | "bytes" 22 | "crypto/rand" 23 | "hash" 24 | "testing" 25 | "testing/quick" 26 | 27 | "github.com/martinlindhe/gogost/gost28147" 28 | ) 29 | 30 | func TestHashInterface(t *testing.T) { 31 | h := New(SboxDefault) 32 | var _ hash.Hash = h 33 | } 34 | 35 | func TestVectors(t *testing.T) { 36 | h := New(SboxDefault) 37 | 38 | if bytes.Compare(h.Sum(nil), []byte{ 39 | 0xce, 0x85, 0xb9, 0x9c, 0xc4, 0x67, 0x52, 0xff, 40 | 0xfe, 0xe3, 0x5c, 0xab, 0x9a, 0x7b, 0x02, 0x78, 41 | 0xab, 0xb4, 0xc2, 0xd2, 0x05, 0x5c, 0xff, 0x68, 42 | 0x5a, 0xf4, 0x91, 0x2c, 0x49, 0x49, 0x0f, 0x8d, 43 | }) != 0 { 44 | t.Fail() 45 | } 46 | 47 | h.Reset() 48 | h.Write([]byte("a")) 49 | if bytes.Compare(h.Sum(nil), []byte{ 50 | 0xd4, 0x2c, 0x53, 0x9e, 0x36, 0x7c, 0x66, 0xe9, 51 | 0xc8, 0x8a, 0x80, 0x1f, 0x66, 0x49, 0x34, 0x9c, 52 | 0x21, 0x87, 0x1b, 0x43, 0x44, 0xc6, 0xa5, 0x73, 53 | 0xf8, 0x49, 0xfd, 0xce, 0x62, 0xf3, 0x14, 0xdd, 54 | }) != 0 { 55 | t.Fail() 56 | } 57 | 58 | h.Reset() 59 | h.Write([]byte("abc")) 60 | if bytes.Compare(h.Sum(nil), []byte{ 61 | 0xf3, 0x13, 0x43, 0x48, 0xc4, 0x4f, 0xb1, 0xb2, 62 | 0xa2, 0x77, 0x72, 0x9e, 0x22, 0x85, 0xeb, 0xb5, 63 | 0xcb, 0x5e, 0x0f, 0x29, 0xc9, 0x75, 0xbc, 0x75, 64 | 0x3b, 0x70, 0x49, 0x7c, 0x06, 0xa4, 0xd5, 0x1d, 65 | }) != 0 { 66 | t.Fail() 67 | } 68 | 69 | h.Reset() 70 | h.Write([]byte("message digest")) 71 | if bytes.Compare(h.Sum(nil), []byte{ 72 | 0xad, 0x44, 0x34, 0xec, 0xb1, 0x8f, 0x2c, 0x99, 73 | 0xb6, 0x0c, 0xbe, 0x59, 0xec, 0x3d, 0x24, 0x69, 74 | 0x58, 0x2b, 0x65, 0x27, 0x3f, 0x48, 0xde, 0x72, 75 | 0xdb, 0x2f, 0xde, 0x16, 0xa4, 0x88, 0x9a, 0x4d, 76 | }) != 0 { 77 | t.Fail() 78 | } 79 | 80 | h.Reset() 81 | for i := 0; i < 128; i++ { 82 | h.Write([]byte("U")) 83 | } 84 | if bytes.Compare(h.Sum(nil), []byte{ 85 | 0x53, 0xa3, 0xa3, 0xed, 0x25, 0x18, 0x0c, 0xef, 86 | 0x0c, 0x1d, 0x85, 0xa0, 0x74, 0x27, 0x3e, 0x55, 87 | 0x1c, 0x25, 0x66, 0x0a, 0x87, 0x06, 0x2a, 0x52, 88 | 0xd9, 0x26, 0xa9, 0xe8, 0xfe, 0x57, 0x33, 0xa4, 89 | }) != 0 { 90 | t.Fail() 91 | } 92 | 93 | h.Reset() 94 | h.Write([]byte("The quick brown fox jumps over the lazy dog")) 95 | if bytes.Compare(h.Sum(nil), []byte{ 96 | 0x77, 0xb7, 0xfa, 0x41, 0x0c, 0x9a, 0xc5, 0x8a, 97 | 0x25, 0xf4, 0x9b, 0xca, 0x7d, 0x04, 0x68, 0xc9, 98 | 0x29, 0x65, 0x29, 0x31, 0x5e, 0xac, 0xa7, 0x6b, 99 | 0xd1, 0xa1, 0x0f, 0x37, 0x6d, 0x1f, 0x42, 0x94, 100 | }) != 0 { 101 | t.Fail() 102 | } 103 | 104 | h.Reset() 105 | h.Write([]byte("The quick brown fox jumps over the lazy cog")) 106 | if bytes.Compare(h.Sum(nil), []byte{ 107 | 0xa3, 0xeb, 0xc4, 0xda, 0xaa, 0xb7, 0x8b, 0x0b, 108 | 0xe1, 0x31, 0xda, 0xb5, 0x73, 0x7a, 0x7f, 0x67, 109 | 0xe6, 0x02, 0x67, 0x0d, 0x54, 0x35, 0x21, 0x31, 110 | 0x91, 0x50, 0xd2, 0xe1, 0x4e, 0xee, 0xc4, 0x45, 111 | }) != 0 { 112 | t.Fail() 113 | } 114 | 115 | h.Reset() 116 | h.Write([]byte("This is message, length=32 bytes")) 117 | if bytes.Compare(h.Sum(nil), []byte{ 118 | 0xb1, 0xc4, 0x66, 0xd3, 0x75, 0x19, 0xb8, 0x2e, 119 | 0x83, 0x19, 0x81, 0x9f, 0xf3, 0x25, 0x95, 0xe0, 120 | 0x47, 0xa2, 0x8c, 0xb6, 0xf8, 0x3e, 0xff, 0x1c, 121 | 0x69, 0x16, 0xa8, 0x15, 0xa6, 0x37, 0xff, 0xfa, 122 | }) != 0 { 123 | t.Fail() 124 | } 125 | 126 | h.Reset() 127 | h.Write([]byte("Suppose the original message has length = 50 bytes")) 128 | if bytes.Compare(h.Sum(nil), []byte{ 129 | 0x47, 0x1a, 0xba, 0x57, 0xa6, 0x0a, 0x77, 0x0d, 130 | 0x3a, 0x76, 0x13, 0x06, 0x35, 0xc1, 0xfb, 0xea, 131 | 0x4e, 0xf1, 0x4d, 0xe5, 0x1f, 0x78, 0xb4, 0xae, 132 | 0x57, 0xdd, 0x89, 0x3b, 0x62, 0xf5, 0x52, 0x08, 133 | }) != 0 { 134 | t.Fail() 135 | } 136 | } 137 | 138 | func TestVectorsCryptoPro(t *testing.T) { 139 | h := New(&gost28147.GostR3411_94_CryptoProParamSet) 140 | 141 | if bytes.Compare(h.Sum(nil), []byte{ 142 | 0x98, 0x1e, 0x5f, 0x3c, 0xa3, 0x0c, 0x84, 0x14, 143 | 0x87, 0x83, 0x0f, 0x84, 0xfb, 0x43, 0x3e, 0x13, 144 | 0xac, 0x11, 0x01, 0x56, 0x9b, 0x9c, 0x13, 0x58, 145 | 0x4a, 0xc4, 0x83, 0x23, 0x4c, 0xd6, 0x56, 0xc0, 146 | }) != 0 { 147 | t.Fail() 148 | } 149 | 150 | h.Reset() 151 | h.Write([]byte("a")) 152 | if bytes.Compare(h.Sum(nil), []byte{ 153 | 0xe7, 0x4c, 0x52, 0xdd, 0x28, 0x21, 0x83, 0xbf, 154 | 0x37, 0xaf, 0x00, 0x79, 0xc9, 0xf7, 0x80, 0x55, 155 | 0x71, 0x5a, 0x10, 0x3f, 0x17, 0xe3, 0x13, 0x3c, 156 | 0xef, 0xf1, 0xaa, 0xcf, 0x2f, 0x40, 0x30, 0x11, 157 | }) != 0 { 158 | t.Fail() 159 | } 160 | 161 | h.Reset() 162 | h.Write([]byte("abc")) 163 | if bytes.Compare(h.Sum(nil), []byte{ 164 | 0xb2, 0x85, 0x05, 0x6d, 0xbf, 0x18, 0xd7, 0x39, 165 | 0x2d, 0x76, 0x77, 0x36, 0x95, 0x24, 0xdd, 0x14, 166 | 0x74, 0x74, 0x59, 0xed, 0x81, 0x43, 0x99, 0x7e, 167 | 0x16, 0x3b, 0x29, 0x86, 0xf9, 0x2f, 0xd4, 0x2c, 168 | }) != 0 { 169 | t.Fail() 170 | } 171 | 172 | h.Reset() 173 | h.Write([]byte("message digest")) 174 | if bytes.Compare(h.Sum(nil), []byte{ 175 | 0xbc, 0x60, 0x41, 0xdd, 0x2a, 0xa4, 0x01, 0xeb, 176 | 0xfa, 0x6e, 0x98, 0x86, 0x73, 0x41, 0x74, 0xfe, 177 | 0xbd, 0xb4, 0x72, 0x9a, 0xa9, 0x72, 0xd6, 0x0f, 178 | 0x54, 0x9a, 0xc3, 0x9b, 0x29, 0x72, 0x1b, 0xa0, 179 | }) != 0 { 180 | t.Fail() 181 | } 182 | 183 | h.Reset() 184 | h.Write([]byte("The quick brown fox jumps over the lazy dog")) 185 | if bytes.Compare(h.Sum(nil), []byte{ 186 | 0x90, 0x04, 0x29, 0x4a, 0x36, 0x1a, 0x50, 0x8c, 187 | 0x58, 0x6f, 0xe5, 0x3d, 0x1f, 0x1b, 0x02, 0x74, 188 | 0x67, 0x65, 0xe7, 0x1b, 0x76, 0x54, 0x72, 0x78, 189 | 0x6e, 0x47, 0x70, 0xd5, 0x65, 0x83, 0x0a, 0x76, 190 | }) != 0 { 191 | t.Fail() 192 | } 193 | 194 | h.Reset() 195 | h.Write([]byte("This is message, length=32 bytes")) 196 | if bytes.Compare(h.Sum(nil), []byte{ 197 | 0x2c, 0xef, 0xc2, 0xf7, 0xb7, 0xbd, 0xc5, 0x14, 198 | 0xe1, 0x8e, 0xa5, 0x7f, 0xa7, 0x4f, 0xf3, 0x57, 199 | 0xe7, 0xfa, 0x17, 0xd6, 0x52, 0xc7, 0x5f, 0x69, 200 | 0xcb, 0x1b, 0xe7, 0x89, 0x3e, 0xde, 0x48, 0xeb, 201 | }) != 0 { 202 | t.Fail() 203 | } 204 | 205 | h.Reset() 206 | h.Write([]byte("Suppose the original message has length = 50 bytes")) 207 | if bytes.Compare(h.Sum(nil), []byte{ 208 | 0xc3, 0x73, 0x0c, 0x5c, 0xbc, 0xca, 0xcf, 0x91, 209 | 0x5a, 0xc2, 0x92, 0x67, 0x6f, 0x21, 0xe8, 0xbd, 210 | 0x4e, 0xf7, 0x53, 0x31, 0xd9, 0x40, 0x5e, 0x5f, 211 | 0x1a, 0x61, 0xdc, 0x31, 0x30, 0xa6, 0x50, 0x11, 212 | }) != 0 { 213 | t.Fail() 214 | } 215 | 216 | h.Reset() 217 | for i := 0; i < 128; i++ { 218 | h.Write([]byte{'U'}) 219 | } 220 | if bytes.Compare(h.Sum(nil), []byte{ 221 | 0x1c, 0x4a, 0xc7, 0x61, 0x46, 0x91, 0xbb, 0xf4, 222 | 0x27, 0xfa, 0x23, 0x16, 0x21, 0x6b, 0xe8, 0xf1, 223 | 0x0d, 0x92, 0xed, 0xfd, 0x37, 0xcd, 0x10, 0x27, 224 | 0x51, 0x4c, 0x10, 0x08, 0xf6, 0x49, 0xc4, 0xe8, 225 | }) != 0 { 226 | t.Fail() 227 | } 228 | } 229 | 230 | func TestRandom(t *testing.T) { 231 | h := New(SboxDefault) 232 | f := func(data []byte) bool { 233 | h.Reset() 234 | h.Write(data) 235 | d1 := h.Sum(nil) 236 | h.Reset() 237 | for _, c := range data { 238 | h.Write([]byte{c}) 239 | } 240 | d2 := h.Sum(nil) 241 | return bytes.Compare(d1, d2) == 0 242 | } 243 | if err := quick.Check(f, nil); err != nil { 244 | t.Error(err) 245 | } 246 | } 247 | 248 | func BenchmarkHash(b *testing.B) { 249 | h := New(SboxDefault) 250 | src := make([]byte, BlockSize+1) 251 | rand.Read(src) 252 | b.ResetTimer() 253 | for i := 0; i < b.N; i++ { 254 | h.Write(src) 255 | h.Sum(nil) 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /gost341194/pbkdf2_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost341194 19 | 20 | import ( 21 | "bytes" 22 | "hash" 23 | "testing" 24 | 25 | "github.com/martinlindhe/gogost/gost28147" 26 | "golang.org/x/crypto/pbkdf2" 27 | ) 28 | 29 | func PBKDF2Hash() hash.Hash { 30 | return New(&gost28147.GostR3411_94_CryptoProParamSet) 31 | } 32 | 33 | // Test vectors for PBKDF2 taken from 34 | // http://tc26.ru/methods/containers_v1/Addition_to_PKCS5_v1_0.pdf test vectors 35 | func TestPBKDF2Vectors(t *testing.T) { 36 | if bytes.Compare(pbkdf2.Key( 37 | []byte("password"), 38 | []byte("salt"), 39 | 1, 40 | 32, 41 | PBKDF2Hash, 42 | ), []byte{0x73, 0x14, 0xe7, 0xc0, 0x4f, 0xb2, 0xe6, 0x62, 0xc5, 0x43, 0x67, 0x42, 0x53, 0xf6, 0x8b, 0xd0, 0xb7, 0x34, 0x45, 0xd0, 0x7f, 0x24, 0x1b, 0xed, 0x87, 0x28, 0x82, 0xda, 0x21, 0x66, 0x2d, 0x58}) != 0 { 43 | t.Fail() 44 | } 45 | if bytes.Compare(pbkdf2.Key( 46 | []byte("password"), 47 | []byte("salt"), 48 | 2, 49 | 32, 50 | PBKDF2Hash, 51 | ), []byte{0x99, 0x0d, 0xfa, 0x2b, 0xd9, 0x65, 0x63, 0x9b, 0xa4, 0x8b, 0x07, 0xb7, 0x92, 0x77, 0x5d, 0xf7, 0x9f, 0x2d, 0xb3, 0x4f, 0xef, 0x25, 0xf2, 0x74, 0x37, 0x88, 0x72, 0xfe, 0xd7, 0xed, 0x1b, 0xb3}) != 0 { 52 | t.Fail() 53 | } 54 | if bytes.Compare(pbkdf2.Key( 55 | []byte("password"), 56 | []byte("salt"), 57 | 4096, 58 | 32, 59 | PBKDF2Hash, 60 | ), []byte{0x1f, 0x18, 0x29, 0xa9, 0x4b, 0xdf, 0xf5, 0xbe, 0x10, 0xd0, 0xae, 0xb3, 0x6a, 0xf4, 0x98, 0xe7, 0xa9, 0x74, 0x67, 0xf3, 0xb3, 0x11, 0x16, 0xa5, 0xa7, 0xc1, 0xaf, 0xff, 0x9d, 0xea, 0xda, 0xfe}) != 0 { 61 | t.Fail() 62 | } 63 | /* 64 | // It takes too long 65 | if bytes.Compare(pbkdf2.Key( 66 | []byte("password"), 67 | []byte("salt"), 68 | 16777216, 69 | 32, 70 | PBKDF2Hash, 71 | ), []byte{0xa5, 0x7a, 0xe5, 0xa6, 0x08, 0x83, 0x96, 0xd1, 0x20, 0x85, 0x0c, 0x5c, 0x09, 0xde, 0x0a, 0x52, 0x51, 0x00, 0x93, 0x8a, 0x59, 0xb1, 0xb5, 0xc3, 0xf7, 0x81, 0x09, 0x10, 0xd0, 0x5f, 0xcd, 0x97}) != 0 { 72 | t.Fail() 73 | } 74 | */ 75 | if bytes.Compare(pbkdf2.Key( 76 | []byte("passwordPASSWORDpassword"), 77 | []byte("saltSALTsaltSALTsaltSALTsaltSALTsalt"), 78 | 4096, 79 | 40, 80 | PBKDF2Hash, 81 | ), []byte{0x78, 0x83, 0x58, 0xc6, 0x9c, 0xb2, 0xdb, 0xe2, 0x51, 0xa7, 0xbb, 0x17, 0xd5, 0xf4, 0x24, 0x1f, 0x26, 0x5a, 0x79, 0x2a, 0x35, 0xbe, 0xcd, 0xe8, 0xd5, 0x6f, 0x32, 0x6b, 0x49, 0xc8, 0x50, 0x47, 0xb7, 0x63, 0x8a, 0xcb, 0x47, 0x64, 0xb1, 0xfd}) != 0 { 82 | t.Fail() 83 | } 84 | if bytes.Compare(pbkdf2.Key( 85 | []byte("pass\x00word"), 86 | []byte("sa\x00lt"), 87 | 4096, 88 | 20, 89 | PBKDF2Hash, 90 | ), []byte{0x43, 0xe0, 0x6c, 0x55, 0x90, 0xb0, 0x8c, 0x02, 0x25, 0x24, 0x23, 0x73, 0x12, 0x7e, 0xdf, 0x9c, 0x8e, 0x9c, 0x32, 0x91}) != 0 { 91 | t.Fail() 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /gost3412/cipher.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST 34.12-2015 128-bit (Кузнечик (Kuznechik)) block cipher. 19 | package gost3412 20 | 21 | const ( 22 | BlockSize = 16 23 | KeySize = 32 24 | ) 25 | 26 | var ( 27 | lc [BlockSize]byte = [BlockSize]byte{ 28 | 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 29 | 133, 32, 148, 1, 30 | } 31 | pi [256]byte = [256]byte{ 32 | 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 33 | 218, 35, 197, 4, 77, 233, 119, 240, 219, 147, 46, 34 | 153, 186, 23, 54, 241, 187, 20, 205, 95, 193, 249, 35 | 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 36 | 1, 142, 79, 5, 132, 2, 174, 227, 106, 143, 160, 6, 37 | 11, 237, 152, 127, 212, 211, 31, 235, 52, 44, 81, 38 | 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 39 | 204, 181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 40 | 71, 156, 183, 93, 135, 21, 161, 150, 41, 16, 123, 41 | 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, 42 | 50, 117, 25, 61, 255, 53, 138, 126, 109, 84, 198, 43 | 128, 195, 189, 13, 87, 223, 245, 36, 169, 62, 168, 44 | 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, 224, 45 | 15, 236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 46 | 78, 51, 10, 74, 167, 151, 96, 115, 30, 0, 98, 68, 47 | 26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70, 48 | 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 49 | 149, 59, 7, 88, 179, 64, 134, 172, 29, 247, 48, 55, 50 | 107, 228, 136, 217, 231, 137, 225, 27, 131, 73, 76, 51 | 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, 52 | 32, 113, 103, 164, 45, 43, 9, 91, 203, 155, 37, 208, 53 | 190, 229, 108, 82, 89, 166, 116, 210, 230, 244, 180, 54 | 192, 209, 102, 175, 194, 57, 75, 99, 182, 55 | } 56 | piInv [256]byte 57 | cBlk [32]*[BlockSize]byte 58 | ) 59 | 60 | func gf(a, b byte) (c byte) { 61 | for b > 0 { 62 | if b&1 > 0 { 63 | c ^= a 64 | } 65 | if a&0x80 > 0 { 66 | a = (a << 1) ^ 0xC3 67 | } else { 68 | a <<= 1 69 | } 70 | b >>= 1 71 | } 72 | return 73 | } 74 | 75 | func l(blk *[BlockSize]byte, rounds int) { 76 | var t byte 77 | var i int 78 | for ; rounds > 0; rounds-- { 79 | t = blk[15] 80 | for i = 14; i >= 0; i-- { 81 | blk[i+1] = blk[i] 82 | t ^= gf(blk[i], lc[i]) 83 | } 84 | blk[0] = t 85 | } 86 | } 87 | 88 | func lInv(blk *[BlockSize]byte) { 89 | var t byte 90 | var i int 91 | for n := 0; n < BlockSize; n++ { 92 | t = blk[0] 93 | for i = 0; i < 15; i++ { 94 | blk[i] = blk[i+1] 95 | t ^= gf(blk[i], lc[i]) 96 | } 97 | blk[15] = t 98 | } 99 | } 100 | 101 | func init() { 102 | piInvP := new([256]byte) 103 | for i := 0; i < 256; i++ { 104 | piInvP[int(pi[i])] = byte(i) 105 | } 106 | piInv = *piInvP 107 | CP := new([32]*[BlockSize]byte) 108 | for i := 0; i < 32; i++ { 109 | CP[i] = new([BlockSize]byte) 110 | CP[i][15] = byte(i) + 1 111 | l(CP[i], 16) 112 | } 113 | cBlk = *CP 114 | } 115 | 116 | func s(blk *[BlockSize]byte) { 117 | for i := 0; i < BlockSize; i++ { 118 | blk[i] = pi[int(blk[i])] 119 | } 120 | } 121 | 122 | func xor(dst, src1, src2 *[BlockSize]byte) { 123 | for i := 0; i < BlockSize; i++ { 124 | dst[i] = src1[i] ^ src2[i] 125 | } 126 | } 127 | 128 | type Cipher struct { 129 | ks [10]*[BlockSize]byte 130 | } 131 | 132 | func (c *Cipher) BlockSize() int { 133 | return BlockSize 134 | } 135 | 136 | func NewCipher(key [KeySize]byte) *Cipher { 137 | ks := new([10]*[BlockSize]byte) 138 | kr0 := new([BlockSize]byte) 139 | kr1 := new([BlockSize]byte) 140 | krt := new([BlockSize]byte) 141 | copy(kr0[:], key[:BlockSize]) 142 | copy(kr1[:], key[BlockSize:]) 143 | ks[0] = new([BlockSize]byte) 144 | ks[1] = new([BlockSize]byte) 145 | copy(ks[0][:], kr0[:]) 146 | copy(ks[1][:], kr1[:]) 147 | for i := 0; i < 4; i++ { 148 | for j := 0; j < 8; j++ { 149 | xor(krt, kr0, cBlk[8*i+j]) 150 | s(krt) 151 | l(krt, 16) 152 | xor(krt, krt, kr1) 153 | copy(kr1[:], kr0[:]) 154 | copy(kr0[:], krt[:]) 155 | } 156 | ks[2+2*i] = new([BlockSize]byte) 157 | copy(ks[2+2*i][:], kr0[:]) 158 | ks[2+2*i+1] = new([BlockSize]byte) 159 | copy(ks[2+2*i+1][:], kr1[:]) 160 | } 161 | return &Cipher{*ks} 162 | } 163 | 164 | func (c *Cipher) Encrypt(dst, src []byte) { 165 | blk := new([BlockSize]byte) 166 | copy(blk[:], src) 167 | for i := 0; i < 9; i++ { 168 | xor(blk, blk, c.ks[i]) 169 | s(blk) 170 | l(blk, 16) 171 | } 172 | xor(blk, blk, c.ks[9]) 173 | copy(dst[:BlockSize], blk[:]) 174 | } 175 | 176 | func (c *Cipher) Decrypt(dst, src []byte) { 177 | blk := new([BlockSize]byte) 178 | copy(blk[:], src) 179 | var n int 180 | for i := 9; i > 0; i-- { 181 | xor(blk, blk, c.ks[i]) 182 | lInv(blk) 183 | for n = 0; n < BlockSize; n++ { 184 | blk[n] = piInv[int(blk[n])] 185 | } 186 | } 187 | xor(blk, blk, c.ks[0]) 188 | copy(dst[:BlockSize], blk[:]) 189 | } 190 | -------------------------------------------------------------------------------- /gost3412/cipher_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost3412 19 | 20 | import ( 21 | "bytes" 22 | "crypto/cipher" 23 | "crypto/rand" 24 | "io" 25 | "testing" 26 | "testing/quick" 27 | ) 28 | 29 | var ( 30 | key [KeySize]byte = [KeySize]byte{ 31 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 32 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 33 | 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 34 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 35 | } 36 | pt [BlockSize]byte = [BlockSize]byte{ 37 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 38 | 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 39 | } 40 | ct [BlockSize]byte = [BlockSize]byte{ 41 | 0x7f, 0x67, 0x9d, 0x90, 0xbe, 0xbc, 0x24, 0x30, 42 | 0x5a, 0x46, 0x8d, 0x42, 0xb9, 0xd4, 0xed, 0xcd, 43 | } 44 | ) 45 | 46 | func TestCipherInterface(t *testing.T) { 47 | var key [32]byte 48 | var _ cipher.Block = NewCipher(key) 49 | } 50 | 51 | func TestRandom(t *testing.T) { 52 | data := make([]byte, BlockSize) 53 | f := func(key [KeySize]byte, pt [BlockSize]byte) bool { 54 | io.ReadFull(rand.Reader, key[:]) 55 | c := NewCipher(key) 56 | c.Encrypt(data, pt[:]) 57 | c.Decrypt(data, data) 58 | return bytes.Compare(data, pt[:]) == 0 59 | } 60 | if err := quick.Check(f, nil); err != nil { 61 | t.Error(err) 62 | } 63 | } 64 | 65 | func BenchmarkEncrypt(b *testing.B) { 66 | var key [KeySize]byte 67 | io.ReadFull(rand.Reader, key[:]) 68 | c := NewCipher(key) 69 | blk := make([]byte, BlockSize) 70 | b.ResetTimer() 71 | for i := 0; i < b.N; i++ { 72 | c.Encrypt(blk, blk) 73 | } 74 | } 75 | 76 | func BenchmarkDecrypt(b *testing.B) { 77 | var key [KeySize]byte 78 | io.ReadFull(rand.Reader, key[:]) 79 | c := NewCipher(key) 80 | blk := make([]byte, BlockSize) 81 | b.ResetTimer() 82 | for i := 0; i < b.N; i++ { 83 | c.Decrypt(blk, blk) 84 | } 85 | } 86 | 87 | func TestS(t *testing.T) { 88 | blk := [BlockSize]byte{ 89 | 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 90 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 91 | } 92 | s(&blk) 93 | if bytes.Compare(blk[:], []byte{ 94 | 0xb6, 0x6c, 0xd8, 0x88, 0x7d, 0x38, 0xe8, 0xd7, 95 | 0x77, 0x65, 0xae, 0xea, 0x0c, 0x9a, 0x7e, 0xfc, 96 | }) != 0 { 97 | t.FailNow() 98 | } 99 | s(&blk) 100 | if bytes.Compare(blk[:], []byte{ 101 | 0x55, 0x9d, 0x8d, 0xd7, 0xbd, 0x06, 0xcb, 0xfe, 102 | 0x7e, 0x7b, 0x26, 0x25, 0x23, 0x28, 0x0d, 0x39, 103 | }) != 0 { 104 | t.FailNow() 105 | } 106 | s(&blk) 107 | if bytes.Compare(blk[:], []byte{ 108 | 0x0c, 0x33, 0x22, 0xfe, 0xd5, 0x31, 0xe4, 0x63, 109 | 0x0d, 0x80, 0xef, 0x5c, 0x5a, 0x81, 0xc5, 0x0b, 110 | }) != 0 { 111 | t.FailNow() 112 | } 113 | s(&blk) 114 | if bytes.Compare(blk[:], []byte{ 115 | 0x23, 0xae, 0x65, 0x63, 0x3f, 0x84, 0x2d, 0x29, 116 | 0xc5, 0xdf, 0x52, 0x9c, 0x13, 0xf5, 0xac, 0xda, 117 | }) != 0 { 118 | t.FailNow() 119 | } 120 | } 121 | 122 | func R(blk *[BlockSize]byte) { 123 | l(blk, 1) 124 | } 125 | 126 | func TestR(t *testing.T) { 127 | blk := [BlockSize]byte{ 128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 130 | } 131 | R(&blk) 132 | if bytes.Compare(blk[:], []byte{ 133 | 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 135 | }) != 0 { 136 | t.FailNow() 137 | } 138 | R(&blk) 139 | if bytes.Compare(blk[:], []byte{ 140 | 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 | }) != 0 { 143 | t.FailNow() 144 | } 145 | R(&blk) 146 | if bytes.Compare(blk[:], []byte{ 147 | 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 149 | }) != 0 { 150 | t.FailNow() 151 | } 152 | R(&blk) 153 | if bytes.Compare(blk[:], []byte{ 154 | 0x0d, 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 | }) != 0 { 157 | t.FailNow() 158 | } 159 | } 160 | 161 | func TestL(t *testing.T) { 162 | blk := [BlockSize]byte{ 163 | 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 165 | } 166 | l(&blk, 16) 167 | if bytes.Compare(blk[:], []byte{ 168 | 0xd4, 0x56, 0x58, 0x4d, 0xd0, 0xe3, 0xe8, 0x4c, 169 | 0xc3, 0x16, 0x6e, 0x4b, 0x7f, 0xa2, 0x89, 0x0d, 170 | }) != 0 { 171 | t.FailNow() 172 | } 173 | l(&blk, 16) 174 | if bytes.Compare(blk[:], []byte{ 175 | 0x79, 0xd2, 0x62, 0x21, 0xb8, 0x7b, 0x58, 0x4c, 176 | 0xd4, 0x2f, 0xbc, 0x4f, 0xfe, 0xa5, 0xde, 0x9a, 177 | }) != 0 { 178 | t.FailNow() 179 | } 180 | l(&blk, 16) 181 | if bytes.Compare(blk[:], []byte{ 182 | 0x0e, 0x93, 0x69, 0x1a, 0x0c, 0xfc, 0x60, 0x40, 183 | 0x8b, 0x7b, 0x68, 0xf6, 0x6b, 0x51, 0x3c, 0x13, 184 | }) != 0 { 185 | t.FailNow() 186 | } 187 | l(&blk, 16) 188 | if bytes.Compare(blk[:], []byte{ 189 | 0xe6, 0xa8, 0x09, 0x4f, 0xee, 0x0a, 0xa2, 0x04, 190 | 0xfd, 0x97, 0xbc, 0xb0, 0xb4, 0x4b, 0x85, 0x80, 191 | }) != 0 { 192 | t.FailNow() 193 | } 194 | } 195 | 196 | func TestC(t *testing.T) { 197 | if bytes.Compare(cBlk[0][:], []byte{ 198 | 0x6e, 0xa2, 0x76, 0x72, 0x6c, 0x48, 0x7a, 0xb8, 199 | 0x5d, 0x27, 0xbd, 0x10, 0xdd, 0x84, 0x94, 0x01, 200 | }) != 0 { 201 | t.FailNow() 202 | } 203 | if bytes.Compare(cBlk[1][:], []byte{ 204 | 0xdc, 0x87, 0xec, 0xe4, 0xd8, 0x90, 0xf4, 0xb3, 205 | 0xba, 0x4e, 0xb9, 0x20, 0x79, 0xcb, 0xeb, 0x02, 206 | }) != 0 { 207 | t.FailNow() 208 | } 209 | if bytes.Compare(cBlk[2][:], []byte{ 210 | 0xb2, 0x25, 0x9a, 0x96, 0xb4, 0xd8, 0x8e, 0x0b, 211 | 0xe7, 0x69, 0x04, 0x30, 0xa4, 0x4f, 0x7f, 0x03, 212 | }) != 0 { 213 | t.FailNow() 214 | } 215 | if bytes.Compare(cBlk[3][:], []byte{ 216 | 0x7b, 0xcd, 0x1b, 0x0b, 0x73, 0xe3, 0x2b, 0xa5, 217 | 0xb7, 0x9c, 0xb1, 0x40, 0xf2, 0x55, 0x15, 0x04, 218 | }) != 0 { 219 | t.FailNow() 220 | } 221 | if bytes.Compare(cBlk[4][:], []byte{ 222 | 0x15, 0x6f, 0x6d, 0x79, 0x1f, 0xab, 0x51, 0x1d, 223 | 0xea, 0xbb, 0x0c, 0x50, 0x2f, 0xd1, 0x81, 0x05, 224 | }) != 0 { 225 | t.FailNow() 226 | } 227 | if bytes.Compare(cBlk[5][:], []byte{ 228 | 0xa7, 0x4a, 0xf7, 0xef, 0xab, 0x73, 0xdf, 0x16, 229 | 0x0d, 0xd2, 0x08, 0x60, 0x8b, 0x9e, 0xfe, 0x06, 230 | }) != 0 { 231 | t.FailNow() 232 | } 233 | if bytes.Compare(cBlk[6][:], []byte{ 234 | 0xc9, 0xe8, 0x81, 0x9d, 0xc7, 0x3b, 0xa5, 0xae, 235 | 0x50, 0xf5, 0xb5, 0x70, 0x56, 0x1a, 0x6a, 0x07, 236 | }) != 0 { 237 | t.FailNow() 238 | } 239 | if bytes.Compare(cBlk[7][:], []byte{ 240 | 0xf6, 0x59, 0x36, 0x16, 0xe6, 0x05, 0x56, 0x89, 241 | 0xad, 0xfb, 0xa1, 0x80, 0x27, 0xaa, 0x2a, 0x08, 242 | }) != 0 { 243 | t.FailNow() 244 | } 245 | } 246 | 247 | func TestRoundKeys(t *testing.T) { 248 | c := NewCipher(key) 249 | if bytes.Compare(c.ks[0][:], []byte{ 250 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 251 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 252 | }) != 0 { 253 | t.FailNow() 254 | } 255 | if bytes.Compare(c.ks[1][:], []byte{ 256 | 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 257 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 258 | }) != 0 { 259 | t.FailNow() 260 | } 261 | if bytes.Compare(c.ks[2][:], []byte{ 262 | 0xdb, 0x31, 0x48, 0x53, 0x15, 0x69, 0x43, 0x43, 263 | 0x22, 0x8d, 0x6a, 0xef, 0x8c, 0xc7, 0x8c, 0x44, 264 | }) != 0 { 265 | t.FailNow() 266 | } 267 | if bytes.Compare(c.ks[3][:], []byte{ 268 | 0x3d, 0x45, 0x53, 0xd8, 0xe9, 0xcf, 0xec, 0x68, 269 | 0x15, 0xeb, 0xad, 0xc4, 0x0a, 0x9f, 0xfd, 0x04, 270 | }) != 0 { 271 | t.FailNow() 272 | } 273 | if bytes.Compare(c.ks[4][:], []byte{ 274 | 0x57, 0x64, 0x64, 0x68, 0xc4, 0x4a, 0x5e, 0x28, 275 | 0xd3, 0xe5, 0x92, 0x46, 0xf4, 0x29, 0xf1, 0xac, 276 | }) != 0 { 277 | t.FailNow() 278 | } 279 | if bytes.Compare(c.ks[5][:], []byte{ 280 | 0xbd, 0x07, 0x94, 0x35, 0x16, 0x5c, 0x64, 0x32, 281 | 0xb5, 0x32, 0xe8, 0x28, 0x34, 0xda, 0x58, 0x1b, 282 | }) != 0 { 283 | t.FailNow() 284 | } 285 | if bytes.Compare(c.ks[6][:], []byte{ 286 | 0x51, 0xe6, 0x40, 0x75, 0x7e, 0x87, 0x45, 0xde, 287 | 0x70, 0x57, 0x27, 0x26, 0x5a, 0x00, 0x98, 0xb1, 288 | }) != 0 { 289 | t.FailNow() 290 | } 291 | if bytes.Compare(c.ks[7][:], []byte{ 292 | 0x5a, 0x79, 0x25, 0x01, 0x7b, 0x9f, 0xdd, 0x3e, 293 | 0xd7, 0x2a, 0x91, 0xa2, 0x22, 0x86, 0xf9, 0x84, 294 | }) != 0 { 295 | t.FailNow() 296 | } 297 | if bytes.Compare(c.ks[8][:], []byte{ 298 | 0xbb, 0x44, 0xe2, 0x53, 0x78, 0xc7, 0x31, 0x23, 299 | 0xa5, 0xf3, 0x2f, 0x73, 0xcd, 0xb6, 0xe5, 0x17, 300 | }) != 0 { 301 | t.FailNow() 302 | } 303 | if bytes.Compare(c.ks[9][:], []byte{ 304 | 0x72, 0xe9, 0xdd, 0x74, 0x16, 0xbc, 0xf4, 0x5b, 305 | 0x75, 0x5d, 0xba, 0xa8, 0x8e, 0x4a, 0x40, 0x43, 306 | }) != 0 { 307 | t.FailNow() 308 | } 309 | } 310 | 311 | func TestVectorEncrypt(t *testing.T) { 312 | c := NewCipher(key) 313 | dst := make([]byte, BlockSize) 314 | c.Encrypt(dst, pt[:]) 315 | if bytes.Compare(dst, ct[:]) != 0 { 316 | t.FailNow() 317 | } 318 | } 319 | 320 | func TestVectorDecrypt(t *testing.T) { 321 | c := NewCipher(key) 322 | dst := make([]byte, BlockSize) 323 | c.Decrypt(dst, ct[:]) 324 | if bytes.Compare(dst, pt[:]) != 0 { 325 | t.FailNow() 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /gost3413/padding.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST R 34.13-2015 padding methods. 19 | package gost3413 20 | 21 | func PadSize(dataSize, blockSize int) int { 22 | if dataSize < blockSize { 23 | return blockSize - dataSize 24 | } 25 | if dataSize%blockSize == 0 { 26 | return 0 27 | } 28 | return blockSize - dataSize%blockSize 29 | } 30 | 31 | func Pad1(data []byte, blockSize int) []byte { 32 | padSize := PadSize(len(data), blockSize) 33 | if padSize == 0 { 34 | return data 35 | } 36 | return append(data, make([]byte, padSize)...) 37 | } 38 | 39 | func Pad2(data []byte, blockSize int) []byte { 40 | pad := make([]byte, 1+PadSize(len(data)+1, blockSize)) 41 | pad[0] = byte(0x80) 42 | return append(data, pad...) 43 | } 44 | 45 | func Pad3(data []byte, blockSize int) []byte { 46 | if PadSize(len(data), blockSize) == 0 { 47 | return data 48 | } 49 | return Pad2(data, blockSize) 50 | } 51 | -------------------------------------------------------------------------------- /internal/gost34112012/hash.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | // GOST R 34.11-2012 hash function. 19 | // RFC 6986. 20 | package gost34112012 21 | 22 | import ( 23 | "encoding/binary" 24 | ) 25 | 26 | const ( 27 | BlockSize = 64 28 | ) 29 | 30 | var ( 31 | pi [256]byte = [256]byte{ 32 | 0xfc, 0xee, 0xdd, 0x11, 0xcf, 0x6e, 0x31, 0x16, 33 | 0xfb, 0xc4, 0xfa, 0xda, 0x23, 0xc5, 0x04, 0x4d, 34 | 0xe9, 0x77, 0xf0, 0xdb, 0x93, 0x2e, 0x99, 0xba, 35 | 0x17, 0x36, 0xf1, 0xbb, 0x14, 0xcd, 0x5f, 0xc1, 36 | 0xf9, 0x18, 0x65, 0x5a, 0xe2, 0x5c, 0xef, 0x21, 37 | 0x81, 0x1c, 0x3c, 0x42, 0x8b, 0x01, 0x8e, 0x4f, 38 | 0x05, 0x84, 0x02, 0xae, 0xe3, 0x6a, 0x8f, 0xa0, 39 | 0x06, 0x0b, 0xed, 0x98, 0x7f, 0xd4, 0xd3, 0x1f, 40 | 0xeb, 0x34, 0x2c, 0x51, 0xea, 0xc8, 0x48, 0xab, 41 | 0xf2, 0x2a, 0x68, 0xa2, 0xfd, 0x3a, 0xce, 0xcc, 42 | 0xb5, 0x70, 0x0e, 0x56, 0x08, 0x0c, 0x76, 0x12, 43 | 0xbf, 0x72, 0x13, 0x47, 0x9c, 0xb7, 0x5d, 0x87, 44 | 0x15, 0xa1, 0x96, 0x29, 0x10, 0x7b, 0x9a, 0xc7, 45 | 0xf3, 0x91, 0x78, 0x6f, 0x9d, 0x9e, 0xb2, 0xb1, 46 | 0x32, 0x75, 0x19, 0x3d, 0xff, 0x35, 0x8a, 0x7e, 47 | 0x6d, 0x54, 0xc6, 0x80, 0xc3, 0xbd, 0x0d, 0x57, 48 | 0xdf, 0xf5, 0x24, 0xa9, 0x3e, 0xa8, 0x43, 0xc9, 49 | 0xd7, 0x79, 0xd6, 0xf6, 0x7c, 0x22, 0xb9, 0x03, 50 | 0xe0, 0x0f, 0xec, 0xde, 0x7a, 0x94, 0xb0, 0xbc, 51 | 0xdc, 0xe8, 0x28, 0x50, 0x4e, 0x33, 0x0a, 0x4a, 52 | 0xa7, 0x97, 0x60, 0x73, 0x1e, 0x00, 0x62, 0x44, 53 | 0x1a, 0xb8, 0x38, 0x82, 0x64, 0x9f, 0x26, 0x41, 54 | 0xad, 0x45, 0x46, 0x92, 0x27, 0x5e, 0x55, 0x2f, 55 | 0x8c, 0xa3, 0xa5, 0x7d, 0x69, 0xd5, 0x95, 0x3b, 56 | 0x07, 0x58, 0xb3, 0x40, 0x86, 0xac, 0x1d, 0xf7, 57 | 0x30, 0x37, 0x6b, 0xe4, 0x88, 0xd9, 0xe7, 0x89, 58 | 0xe1, 0x1b, 0x83, 0x49, 0x4c, 0x3f, 0xf8, 0xfe, 59 | 0x8d, 0x53, 0xaa, 0x90, 0xca, 0xd8, 0x85, 0x61, 60 | 0x20, 0x71, 0x67, 0xa4, 0x2d, 0x2b, 0x09, 0x5b, 61 | 0xcb, 0x9b, 0x25, 0xd0, 0xbe, 0xe5, 0x6c, 0x52, 62 | 0x59, 0xa6, 0x74, 0xd2, 0xe6, 0xf4, 0xb4, 0xc0, 63 | 0xd1, 0x66, 0xaf, 0xc2, 0x39, 0x4b, 0x63, 0xb6, 64 | } 65 | tau [64]int = [64]int{ 66 | 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 67 | 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39, 68 | 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a, 69 | 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b, 70 | 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c, 71 | 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d, 72 | 0x06, 0x0e, 0x16, 0x1e, 0x26, 0x2e, 0x36, 0x3e, 73 | 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 74 | } 75 | c [12][BlockSize]byte = [12][BlockSize]byte{ 76 | [BlockSize]byte{ 77 | 0x07, 0x45, 0xa6, 0xf2, 0x59, 0x65, 0x80, 0xdd, 78 | 0x23, 0x4d, 0x74, 0xcc, 0x36, 0x74, 0x76, 0x05, 79 | 0x15, 0xd3, 0x60, 0xa4, 0x08, 0x2a, 0x42, 0xa2, 80 | 0x01, 0x69, 0x67, 0x92, 0x91, 0xe0, 0x7c, 0x4b, 81 | 0xfc, 0xc4, 0x85, 0x75, 0x8d, 0xb8, 0x4e, 0x71, 82 | 0x16, 0xd0, 0x45, 0x2e, 0x43, 0x76, 0x6a, 0x2f, 83 | 0x1f, 0x7c, 0x65, 0xc0, 0x81, 0x2f, 0xcb, 0xeb, 84 | 0xe9, 0xda, 0xca, 0x1e, 0xda, 0x5b, 0x08, 0xb1, 85 | }, 86 | [BlockSize]byte{ 87 | 0xb7, 0x9b, 0xb1, 0x21, 0x70, 0x04, 0x79, 0xe6, 88 | 0x56, 0xcd, 0xcb, 0xd7, 0x1b, 0xa2, 0xdd, 0x55, 89 | 0xca, 0xa7, 0x0a, 0xdb, 0xc2, 0x61, 0xb5, 0x5c, 90 | 0x58, 0x99, 0xd6, 0x12, 0x6b, 0x17, 0xb5, 0x9a, 91 | 0x31, 0x01, 0xb5, 0x16, 0x0f, 0x5e, 0xd5, 0x61, 92 | 0x98, 0x2b, 0x23, 0x0a, 0x72, 0xea, 0xfe, 0xf3, 93 | 0xd7, 0xb5, 0x70, 0x0f, 0x46, 0x9d, 0xe3, 0x4f, 94 | 0x1a, 0x2f, 0x9d, 0xa9, 0x8a, 0xb5, 0xa3, 0x6f, 95 | }, 96 | [BlockSize]byte{ 97 | 0xb2, 0x0a, 0xba, 0x0a, 0xf5, 0x96, 0x1e, 0x99, 98 | 0x31, 0xdb, 0x7a, 0x86, 0x43, 0xf4, 0xb6, 0xc2, 99 | 0x09, 0xdb, 0x62, 0x60, 0x37, 0x3a, 0xc9, 0xc1, 100 | 0xb1, 0x9e, 0x35, 0x90, 0xe4, 0x0f, 0xe2, 0xd3, 101 | 0x7b, 0x7b, 0x29, 0xb1, 0x14, 0x75, 0xea, 0xf2, 102 | 0x8b, 0x1f, 0x9c, 0x52, 0x5f, 0x5e, 0xf1, 0x06, 103 | 0x35, 0x84, 0x3d, 0x6a, 0x28, 0xfc, 0x39, 0x0a, 104 | 0xc7, 0x2f, 0xce, 0x2b, 0xac, 0xdc, 0x74, 0xf5, 105 | }, 106 | [BlockSize]byte{ 107 | 0x2e, 0xd1, 0xe3, 0x84, 0xbc, 0xbe, 0x0c, 0x22, 108 | 0xf1, 0x37, 0xe8, 0x93, 0xa1, 0xea, 0x53, 0x34, 109 | 0xbe, 0x03, 0x52, 0x93, 0x33, 0x13, 0xb7, 0xd8, 110 | 0x75, 0xd6, 0x03, 0xed, 0x82, 0x2c, 0xd7, 0xa9, 111 | 0x3f, 0x35, 0x5e, 0x68, 0xad, 0x1c, 0x72, 0x9d, 112 | 0x7d, 0x3c, 0x5c, 0x33, 0x7e, 0x85, 0x8e, 0x48, 113 | 0xdd, 0xe4, 0x71, 0x5d, 0xa0, 0xe1, 0x48, 0xf9, 114 | 0xd2, 0x66, 0x15, 0xe8, 0xb3, 0xdf, 0x1f, 0xef, 115 | }, 116 | [BlockSize]byte{ 117 | 0x57, 0xfe, 0x6c, 0x7c, 0xfd, 0x58, 0x17, 0x60, 118 | 0xf5, 0x63, 0xea, 0xa9, 0x7e, 0xa2, 0x56, 0x7a, 119 | 0x16, 0x1a, 0x27, 0x23, 0xb7, 0x00, 0xff, 0xdf, 120 | 0xa3, 0xf5, 0x3a, 0x25, 0x47, 0x17, 0xcd, 0xbf, 121 | 0xbd, 0xff, 0x0f, 0x80, 0xd7, 0x35, 0x9e, 0x35, 122 | 0x4a, 0x10, 0x86, 0x16, 0x1f, 0x1c, 0x15, 0x7f, 123 | 0x63, 0x23, 0xa9, 0x6c, 0x0c, 0x41, 0x3f, 0x9a, 124 | 0x99, 0x47, 0x47, 0xad, 0xac, 0x6b, 0xea, 0x4b, 125 | }, 126 | [BlockSize]byte{ 127 | 0x6e, 0x7d, 0x64, 0x46, 0x7a, 0x40, 0x68, 0xfa, 128 | 0x35, 0x4f, 0x90, 0x36, 0x72, 0xc5, 0x71, 0xbf, 129 | 0xb6, 0xc6, 0xbe, 0xc2, 0x66, 0x1f, 0xf2, 0x0a, 130 | 0xb4, 0xb7, 0x9a, 0x1c, 0xb7, 0xa6, 0xfa, 0xcf, 131 | 0xc6, 0x8e, 0xf0, 0x9a, 0xb4, 0x9a, 0x7f, 0x18, 132 | 0x6c, 0xa4, 0x42, 0x51, 0xf9, 0xc4, 0x66, 0x2d, 133 | 0xc0, 0x39, 0x30, 0x7a, 0x3b, 0xc3, 0xa4, 0x6f, 134 | 0xd9, 0xd3, 0x3a, 0x1d, 0xae, 0xae, 0x4f, 0xae, 135 | }, 136 | [BlockSize]byte{ 137 | 0x93, 0xd4, 0x14, 0x3a, 0x4d, 0x56, 0x86, 0x88, 138 | 0xf3, 0x4a, 0x3c, 0xa2, 0x4c, 0x45, 0x17, 0x35, 139 | 0x04, 0x05, 0x4a, 0x28, 0x83, 0x69, 0x47, 0x06, 140 | 0x37, 0x2c, 0x82, 0x2d, 0xc5, 0xab, 0x92, 0x09, 141 | 0xc9, 0x93, 0x7a, 0x19, 0x33, 0x3e, 0x47, 0xd3, 142 | 0xc9, 0x87, 0xbf, 0xe6, 0xc7, 0xc6, 0x9e, 0x39, 143 | 0x54, 0x09, 0x24, 0xbf, 0xfe, 0x86, 0xac, 0x51, 144 | 0xec, 0xc5, 0xaa, 0xee, 0x16, 0x0e, 0xc7, 0xf4, 145 | }, 146 | [BlockSize]byte{ 147 | 0x1e, 0xe7, 0x02, 0xbf, 0xd4, 0x0d, 0x7f, 0xa4, 148 | 0xd9, 0xa8, 0x51, 0x59, 0x35, 0xc2, 0xac, 0x36, 149 | 0x2f, 0xc4, 0xa5, 0xd1, 0x2b, 0x8d, 0xd1, 0x69, 150 | 0x90, 0x06, 0x9b, 0x92, 0xcb, 0x2b, 0x89, 0xf4, 151 | 0x9a, 0xc4, 0xdb, 0x4d, 0x3b, 0x44, 0xb4, 0x89, 152 | 0x1e, 0xde, 0x36, 0x9c, 0x71, 0xf8, 0xb7, 0x4e, 153 | 0x41, 0x41, 0x6e, 0x0c, 0x02, 0xaa, 0xe7, 0x03, 154 | 0xa7, 0xc9, 0x93, 0x4d, 0x42, 0x5b, 0x1f, 0x9b, 155 | }, 156 | [BlockSize]byte{ 157 | 0xdb, 0x5a, 0x23, 0x83, 0x51, 0x44, 0x61, 0x72, 158 | 0x60, 0x2a, 0x1f, 0xcb, 0x92, 0xdc, 0x38, 0x0e, 159 | 0x54, 0x9c, 0x07, 0xa6, 0x9a, 0x8a, 0x2b, 0x7b, 160 | 0xb1, 0xce, 0xb2, 0xdb, 0x0b, 0x44, 0x0a, 0x80, 161 | 0x84, 0x09, 0x0d, 0xe0, 0xb7, 0x55, 0xd9, 0x3c, 162 | 0x24, 0x42, 0x89, 0x25, 0x1b, 0x3a, 0x7d, 0x3a, 163 | 0xde, 0x5f, 0x16, 0xec, 0xd8, 0x9a, 0x4c, 0x94, 164 | 0x9b, 0x22, 0x31, 0x16, 0x54, 0x5a, 0x8f, 0x37, 165 | }, 166 | [BlockSize]byte{ 167 | 0xed, 0x9c, 0x45, 0x98, 0xfb, 0xc7, 0xb4, 0x74, 168 | 0xc3, 0xb6, 0x3b, 0x15, 0xd1, 0xfa, 0x98, 0x36, 169 | 0xf4, 0x52, 0x76, 0x3b, 0x30, 0x6c, 0x1e, 0x7a, 170 | 0x4b, 0x33, 0x69, 0xaf, 0x02, 0x67, 0xe7, 0x9f, 171 | 0x03, 0x61, 0x33, 0x1b, 0x8a, 0xe1, 0xff, 0x1f, 172 | 0xdb, 0x78, 0x8a, 0xff, 0x1c, 0xe7, 0x41, 0x89, 173 | 0xf3, 0xf3, 0xe4, 0xb2, 0x48, 0xe5, 0x2a, 0x38, 174 | 0x52, 0x6f, 0x05, 0x80, 0xa6, 0xde, 0xbe, 0xab, 175 | }, 176 | [BlockSize]byte{ 177 | 0x1b, 0x2d, 0xf3, 0x81, 0xcd, 0xa4, 0xca, 0x6b, 178 | 0x5d, 0xd8, 0x6f, 0xc0, 0x4a, 0x59, 0xa2, 0xde, 179 | 0x98, 0x6e, 0x47, 0x7d, 0x1d, 0xcd, 0xba, 0xef, 180 | 0xca, 0xb9, 0x48, 0xea, 0xef, 0x71, 0x1d, 0x8a, 181 | 0x79, 0x66, 0x84, 0x14, 0x21, 0x80, 0x01, 0x20, 182 | 0x61, 0x07, 0xab, 0xeb, 0xbb, 0x6b, 0xfa, 0xd8, 183 | 0x94, 0xfe, 0x5a, 0x63, 0xcd, 0xc6, 0x02, 0x30, 184 | 0xfb, 0x89, 0xc8, 0xef, 0xd0, 0x9e, 0xcd, 0x7b, 185 | }, 186 | [BlockSize]byte{ 187 | 0x20, 0xd7, 0x1b, 0xf1, 0x4a, 0x92, 0xbc, 0x48, 188 | 0x99, 0x1b, 0xb2, 0xd9, 0xd5, 0x17, 0xf4, 0xfa, 189 | 0x52, 0x28, 0xe1, 0x88, 0xaa, 0xa4, 0x1d, 0xe7, 190 | 0x86, 0xcc, 0x91, 0x18, 0x9d, 0xef, 0x80, 0x5d, 191 | 0x9b, 0x9f, 0x21, 0x30, 0xd4, 0x12, 0x20, 0xf8, 192 | 0x77, 0x1d, 0xdf, 0xbc, 0x32, 0x3c, 0xa4, 0xcd, 193 | 0x7a, 0xb1, 0x49, 0x04, 0xb0, 0x80, 0x13, 0xd2, 194 | 0xba, 0x31, 0x16, 0xf1, 0x67, 0xe7, 0x8e, 0x37, 195 | }, 196 | } 197 | a [64]uint64 // It is filled in init() 198 | ) 199 | 200 | func init() { 201 | as := [64][]byte{ 202 | []byte{0x8e, 0x20, 0xfa, 0xa7, 0x2b, 0xa0, 0xb4, 0x70}, 203 | []byte{0x47, 0x10, 0x7d, 0xdd, 0x9b, 0x50, 0x5a, 0x38}, 204 | []byte{0xad, 0x08, 0xb0, 0xe0, 0xc3, 0x28, 0x2d, 0x1c}, 205 | []byte{0xd8, 0x04, 0x58, 0x70, 0xef, 0x14, 0x98, 0x0e}, 206 | []byte{0x6c, 0x02, 0x2c, 0x38, 0xf9, 0x0a, 0x4c, 0x07}, 207 | []byte{0x36, 0x01, 0x16, 0x1c, 0xf2, 0x05, 0x26, 0x8d}, 208 | []byte{0x1b, 0x8e, 0x0b, 0x0e, 0x79, 0x8c, 0x13, 0xc8}, 209 | []byte{0x83, 0x47, 0x8b, 0x07, 0xb2, 0x46, 0x87, 0x64}, 210 | []byte{0xa0, 0x11, 0xd3, 0x80, 0x81, 0x8e, 0x8f, 0x40}, 211 | []byte{0x50, 0x86, 0xe7, 0x40, 0xce, 0x47, 0xc9, 0x20}, 212 | []byte{0x28, 0x43, 0xfd, 0x20, 0x67, 0xad, 0xea, 0x10}, 213 | []byte{0x14, 0xaf, 0xf0, 0x10, 0xbd, 0xd8, 0x75, 0x08}, 214 | []byte{0x0a, 0xd9, 0x78, 0x08, 0xd0, 0x6c, 0xb4, 0x04}, 215 | []byte{0x05, 0xe2, 0x3c, 0x04, 0x68, 0x36, 0x5a, 0x02}, 216 | []byte{0x8c, 0x71, 0x1e, 0x02, 0x34, 0x1b, 0x2d, 0x01}, 217 | []byte{0x46, 0xb6, 0x0f, 0x01, 0x1a, 0x83, 0x98, 0x8e}, 218 | []byte{0x90, 0xda, 0xb5, 0x2a, 0x38, 0x7a, 0xe7, 0x6f}, 219 | []byte{0x48, 0x6d, 0xd4, 0x15, 0x1c, 0x3d, 0xfd, 0xb9}, 220 | []byte{0x24, 0xb8, 0x6a, 0x84, 0x0e, 0x90, 0xf0, 0xd2}, 221 | []byte{0x12, 0x5c, 0x35, 0x42, 0x07, 0x48, 0x78, 0x69}, 222 | []byte{0x09, 0x2e, 0x94, 0x21, 0x8d, 0x24, 0x3c, 0xba}, 223 | []byte{0x8a, 0x17, 0x4a, 0x9e, 0xc8, 0x12, 0x1e, 0x5d}, 224 | []byte{0x45, 0x85, 0x25, 0x4f, 0x64, 0x09, 0x0f, 0xa0}, 225 | []byte{0xac, 0xcc, 0x9c, 0xa9, 0x32, 0x8a, 0x89, 0x50}, 226 | []byte{0x9d, 0x4d, 0xf0, 0x5d, 0x5f, 0x66, 0x14, 0x51}, 227 | []byte{0xc0, 0xa8, 0x78, 0xa0, 0xa1, 0x33, 0x0a, 0xa6}, 228 | []byte{0x60, 0x54, 0x3c, 0x50, 0xde, 0x97, 0x05, 0x53}, 229 | []byte{0x30, 0x2a, 0x1e, 0x28, 0x6f, 0xc5, 0x8c, 0xa7}, 230 | []byte{0x18, 0x15, 0x0f, 0x14, 0xb9, 0xec, 0x46, 0xdd}, 231 | []byte{0x0c, 0x84, 0x89, 0x0a, 0xd2, 0x76, 0x23, 0xe0}, 232 | []byte{0x06, 0x42, 0xca, 0x05, 0x69, 0x3b, 0x9f, 0x70}, 233 | []byte{0x03, 0x21, 0x65, 0x8c, 0xba, 0x93, 0xc1, 0x38}, 234 | []byte{0x86, 0x27, 0x5d, 0xf0, 0x9c, 0xe8, 0xaa, 0xa8}, 235 | []byte{0x43, 0x9d, 0xa0, 0x78, 0x4e, 0x74, 0x55, 0x54}, 236 | []byte{0xaf, 0xc0, 0x50, 0x3c, 0x27, 0x3a, 0xa4, 0x2a}, 237 | []byte{0xd9, 0x60, 0x28, 0x1e, 0x9d, 0x1d, 0x52, 0x15}, 238 | []byte{0xe2, 0x30, 0x14, 0x0f, 0xc0, 0x80, 0x29, 0x84}, 239 | []byte{0x71, 0x18, 0x0a, 0x89, 0x60, 0x40, 0x9a, 0x42}, 240 | []byte{0xb6, 0x0c, 0x05, 0xca, 0x30, 0x20, 0x4d, 0x21}, 241 | []byte{0x5b, 0x06, 0x8c, 0x65, 0x18, 0x10, 0xa8, 0x9e}, 242 | []byte{0x45, 0x6c, 0x34, 0x88, 0x7a, 0x38, 0x05, 0xb9}, 243 | []byte{0xac, 0x36, 0x1a, 0x44, 0x3d, 0x1c, 0x8c, 0xd2}, 244 | []byte{0x56, 0x1b, 0x0d, 0x22, 0x90, 0x0e, 0x46, 0x69}, 245 | []byte{0x2b, 0x83, 0x88, 0x11, 0x48, 0x07, 0x23, 0xba}, 246 | []byte{0x9b, 0xcf, 0x44, 0x86, 0x24, 0x8d, 0x9f, 0x5d}, 247 | []byte{0xc3, 0xe9, 0x22, 0x43, 0x12, 0xc8, 0xc1, 0xa0}, 248 | []byte{0xef, 0xfa, 0x11, 0xaf, 0x09, 0x64, 0xee, 0x50}, 249 | []byte{0xf9, 0x7d, 0x86, 0xd9, 0x8a, 0x32, 0x77, 0x28}, 250 | []byte{0xe4, 0xfa, 0x20, 0x54, 0xa8, 0x0b, 0x32, 0x9c}, 251 | []byte{0x72, 0x7d, 0x10, 0x2a, 0x54, 0x8b, 0x19, 0x4e}, 252 | []byte{0x39, 0xb0, 0x08, 0x15, 0x2a, 0xcb, 0x82, 0x27}, 253 | []byte{0x92, 0x58, 0x04, 0x84, 0x15, 0xeb, 0x41, 0x9d}, 254 | []byte{0x49, 0x2c, 0x02, 0x42, 0x84, 0xfb, 0xae, 0xc0}, 255 | []byte{0xaa, 0x16, 0x01, 0x21, 0x42, 0xf3, 0x57, 0x60}, 256 | []byte{0x55, 0x0b, 0x8e, 0x9e, 0x21, 0xf7, 0xa5, 0x30}, 257 | []byte{0xa4, 0x8b, 0x47, 0x4f, 0x9e, 0xf5, 0xdc, 0x18}, 258 | []byte{0x70, 0xa6, 0xa5, 0x6e, 0x24, 0x40, 0x59, 0x8e}, 259 | []byte{0x38, 0x53, 0xdc, 0x37, 0x12, 0x20, 0xa2, 0x47}, 260 | []byte{0x1c, 0xa7, 0x6e, 0x95, 0x09, 0x10, 0x51, 0xad}, 261 | []byte{0x0e, 0xdd, 0x37, 0xc4, 0x8a, 0x08, 0xa6, 0xd8}, 262 | []byte{0x07, 0xe0, 0x95, 0x62, 0x45, 0x04, 0x53, 0x6c}, 263 | []byte{0x8d, 0x70, 0xc4, 0x31, 0xac, 0x02, 0xa7, 0x36}, 264 | []byte{0xc8, 0x38, 0x62, 0x96, 0x56, 0x01, 0xdd, 0x1b}, 265 | []byte{0x64, 0x1c, 0x31, 0x4b, 0x2b, 0x8e, 0xe0, 0x83}, 266 | } 267 | for i := 0; i < 64; i++ { 268 | a[i] = binary.BigEndian.Uint64(as[i]) 269 | } 270 | } 271 | 272 | type Hash struct { 273 | size int 274 | buf []byte 275 | n uint64 276 | hsh *[BlockSize]byte 277 | chk *[BlockSize]byte 278 | tmp *[BlockSize]byte 279 | } 280 | 281 | // Create new hash object with specified size digest size. 282 | func New(size int) *Hash { 283 | if size != 32 && size != 64 { 284 | panic("size must be either 32 or 64") 285 | } 286 | h := Hash{ 287 | size: size, 288 | hsh: new([BlockSize]byte), 289 | chk: new([BlockSize]byte), 290 | tmp: new([BlockSize]byte), 291 | } 292 | h.Reset() 293 | return &h 294 | } 295 | 296 | func (h *Hash) Reset() { 297 | h.n = 0 298 | h.buf = nil 299 | for i := 0; i < BlockSize; i++ { 300 | h.chk[i] = 0 301 | if h.size == 32 { 302 | h.hsh[i] = 1 303 | } else { 304 | h.hsh[i] = 0 305 | } 306 | } 307 | } 308 | 309 | func (h *Hash) BlockSize() int { 310 | return BlockSize 311 | } 312 | 313 | func (h *Hash) Size() int { 314 | return h.size 315 | } 316 | 317 | func (h *Hash) Write(data []byte) (int, error) { 318 | h.buf = append(h.buf, data...) 319 | for len(h.buf) >= BlockSize { 320 | copy(h.tmp[:], h.buf[:BlockSize]) 321 | h.hsh = g(h.n, h.hsh, h.tmp) 322 | h.chk = add512bit(h.chk, h.tmp) 323 | h.n += BlockSize * 8 324 | h.buf = h.buf[BlockSize:] 325 | } 326 | return len(data), nil 327 | } 328 | 329 | func (h *Hash) Sum(in []byte) []byte { 330 | buf := new([BlockSize]byte) 331 | copy(h.tmp[:], buf[:]) 332 | copy(buf[:], h.buf[:]) 333 | buf[len(h.buf)] = 1 334 | hsh := g(h.n, h.hsh, buf) 335 | binary.LittleEndian.PutUint64(h.tmp[:], h.n+uint64(len(h.buf))*8) 336 | hsh = g(0, hsh, h.tmp) 337 | hsh = g(0, hsh, add512bit(h.chk, buf)) 338 | if h.size == 32 { 339 | return append(in, hsh[BlockSize/2:]...) 340 | } 341 | return append(in, hsh[:]...) 342 | } 343 | 344 | func add512bit(chk, data *[BlockSize]byte) *[BlockSize]byte { 345 | var ss uint16 346 | r := new([BlockSize]byte) 347 | for i := 0; i < BlockSize; i++ { 348 | ss = uint16(chk[i]) + uint16(data[i]) + (ss >> 8) 349 | r[i] = byte(0xFF & ss) 350 | } 351 | return r 352 | } 353 | 354 | func g(n uint64, hsh, data *[BlockSize]byte) *[BlockSize]byte { 355 | ns := make([]byte, 8) 356 | binary.LittleEndian.PutUint64(ns, n) 357 | r := new([BlockSize]byte) 358 | for i := 0; i < 8; i++ { 359 | r[i] = hsh[i] ^ ns[i] 360 | } 361 | copy(r[8:], hsh[8:]) 362 | return blockXor(blockXor(e(l(ps(r)), data), hsh), data) 363 | } 364 | 365 | func e(k, msg *[BlockSize]byte) *[BlockSize]byte { 366 | for i := 0; i < 12; i++ { 367 | msg = l(ps(blockXor(k, msg))) 368 | k = l(ps(blockXor(k, &c[i]))) 369 | } 370 | return blockXor(k, msg) 371 | } 372 | 373 | func blockXor(x, y *[BlockSize]byte) *[BlockSize]byte { 374 | r := new([BlockSize]byte) 375 | for i := 0; i < BlockSize; i++ { 376 | r[i] = x[i] ^ y[i] 377 | } 378 | return r 379 | } 380 | 381 | func ps(data *[BlockSize]byte) *[BlockSize]byte { 382 | r := new([BlockSize]byte) 383 | for i := 0; i < BlockSize; i++ { 384 | r[tau[i]] = pi[int(data[i])] 385 | } 386 | return r 387 | } 388 | 389 | func l(data *[BlockSize]byte) *[BlockSize]byte { 390 | var val uint64 391 | var res64 uint64 392 | var j int 393 | r := new([BlockSize]byte) 394 | for i := 0; i < 8; i++ { 395 | val = binary.LittleEndian.Uint64(data[i*8 : i*8+8]) 396 | res64 = 0 397 | for j = 0; j < BlockSize; j++ { 398 | if val&0x8000000000000000 > 0 { 399 | res64 ^= a[j] 400 | } 401 | val <<= 1 402 | } 403 | binary.LittleEndian.PutUint64(r[i*8:i*8+8], res64) 404 | } 405 | return r 406 | } 407 | -------------------------------------------------------------------------------- /internal/gost34112012/hash_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost34112012 19 | 20 | import ( 21 | "bytes" 22 | "crypto/rand" 23 | "hash" 24 | "testing" 25 | "testing/quick" 26 | ) 27 | 28 | func TestHashInterface(t *testing.T) { 29 | h := New(64) 30 | var _ hash.Hash = h 31 | } 32 | 33 | func TestVectors(t *testing.T) { 34 | h512 := New(64) 35 | h256 := New(32) 36 | 37 | // First vector 38 | m := []byte{ 39 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 40 | 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 41 | 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 42 | 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 43 | 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 44 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 45 | 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 46 | 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 47 | } 48 | h512.Write(m) 49 | if bytes.Compare(h512.Sum(nil), []byte{ 50 | 0x1b, 0x54, 0xd0, 0x1a, 0x4a, 0xf5, 0xb9, 0xd5, 51 | 0xcc, 0x3d, 0x86, 0xd6, 0x8d, 0x28, 0x54, 0x62, 52 | 0xb1, 0x9a, 0xbc, 0x24, 0x75, 0x22, 0x2f, 0x35, 53 | 0xc0, 0x85, 0x12, 0x2b, 0xe4, 0xba, 0x1f, 0xfa, 54 | 0x00, 0xad, 0x30, 0xf8, 0x76, 0x7b, 0x3a, 0x82, 55 | 0x38, 0x4c, 0x65, 0x74, 0xf0, 0x24, 0xc3, 0x11, 56 | 0xe2, 0xa4, 0x81, 0x33, 0x2b, 0x08, 0xef, 0x7f, 57 | 0x41, 0x79, 0x78, 0x91, 0xc1, 0x64, 0x6f, 0x48, 58 | }) != 0 { 59 | t.Fail() 60 | } 61 | h256.Write(m) 62 | if bytes.Compare(h256.Sum(nil), []byte{ 63 | 0x9d, 0x15, 0x1e, 0xef, 0xd8, 0x59, 0x0b, 0x89, 64 | 0xda, 0xa6, 0xba, 0x6c, 0xb7, 0x4a, 0xf9, 0x27, 65 | 0x5d, 0xd0, 0x51, 0x02, 0x6b, 0xb1, 0x49, 0xa4, 66 | 0x52, 0xfd, 0x84, 0xe5, 0xe5, 0x7b, 0x55, 0x00, 67 | }) != 0 { 68 | t.Fail() 69 | } 70 | 71 | // Second vector 72 | h512.Reset() 73 | h256.Reset() 74 | m = []byte{ 75 | 0xd1, 0xe5, 0x20, 0xe2, 0xe5, 0xf2, 0xf0, 0xe8, 76 | 0x2c, 0x20, 0xd1, 0xf2, 0xf0, 0xe8, 0xe1, 0xee, 77 | 0xe6, 0xe8, 0x20, 0xe2, 0xed, 0xf3, 0xf6, 0xe8, 78 | 0x2c, 0x20, 0xe2, 0xe5, 0xfe, 0xf2, 0xfa, 0x20, 79 | 0xf1, 0x20, 0xec, 0xee, 0xf0, 0xff, 0x20, 0xf1, 80 | 0xf2, 0xf0, 0xe5, 0xeb, 0xe0, 0xec, 0xe8, 0x20, 81 | 0xed, 0xe0, 0x20, 0xf5, 0xf0, 0xe0, 0xe1, 0xf0, 82 | 0xfb, 0xff, 0x20, 0xef, 0xeb, 0xfa, 0xea, 0xfb, 83 | 0x20, 0xc8, 0xe3, 0xee, 0xf0, 0xe5, 0xe2, 0xfb, 84 | } 85 | h512.Write(m) 86 | if bytes.Compare(h512.Sum(nil), []byte{ 87 | 0x1e, 0x88, 0xe6, 0x22, 0x26, 0xbf, 0xca, 0x6f, 88 | 0x99, 0x94, 0xf1, 0xf2, 0xd5, 0x15, 0x69, 0xe0, 89 | 0xda, 0xf8, 0x47, 0x5a, 0x3b, 0x0f, 0xe6, 0x1a, 90 | 0x53, 0x00, 0xee, 0xe4, 0x6d, 0x96, 0x13, 0x76, 91 | 0x03, 0x5f, 0xe8, 0x35, 0x49, 0xad, 0xa2, 0xb8, 92 | 0x62, 0x0f, 0xcd, 0x7c, 0x49, 0x6c, 0xe5, 0xb3, 93 | 0x3f, 0x0c, 0xb9, 0xdd, 0xdc, 0x2b, 0x64, 0x60, 94 | 0x14, 0x3b, 0x03, 0xda, 0xba, 0xc9, 0xfb, 0x28, 95 | }) != 0 { 96 | t.Fail() 97 | } 98 | h256.Write(m) 99 | if bytes.Compare(h256.Sum(nil), []byte{ 100 | 0x9d, 0xd2, 0xfe, 0x4e, 0x90, 0x40, 0x9e, 0x5d, 101 | 0xa8, 0x7f, 0x53, 0x97, 0x6d, 0x74, 0x05, 0xb0, 102 | 0xc0, 0xca, 0xc6, 0x28, 0xfc, 0x66, 0x9a, 0x74, 103 | 0x1d, 0x50, 0x06, 0x3c, 0x55, 0x7e, 0x8f, 0x50, 104 | }) != 0 { 105 | t.Fail() 106 | } 107 | } 108 | 109 | func TestBlocksized(t *testing.T) { 110 | h := New(64) 111 | m := make([]byte, BlockSize) 112 | for i := 0; i < BlockSize; i++ { 113 | m[i] = byte(i) 114 | } 115 | h.Write(m) 116 | if bytes.Compare(h.Sum(nil), []byte{ 117 | 0x2a, 0xe5, 0x81, 0xf1, 0x8a, 0xe8, 0x5e, 0x35, 118 | 0x96, 0xc9, 0x36, 0xac, 0xbe, 0xf9, 0x10, 0xf2, 119 | 0xed, 0x70, 0xdc, 0xf9, 0x1e, 0xd5, 0xd2, 0x4b, 120 | 0x39, 0xa5, 0xaf, 0x65, 0x7b, 0xf8, 0x23, 0x2a, 121 | 0x30, 0x3d, 0x68, 0x60, 0x56, 0xc8, 0xc0, 0x0b, 122 | 0xf3, 0x0d, 0x42, 0xe1, 0x6c, 0xe2, 0x55, 0x42, 123 | 0x6f, 0xa8, 0xa1, 0x55, 0xdc, 0xb3, 0xeb, 0x82, 124 | 0x2d, 0x92, 0x58, 0x08, 0xf7, 0xc7, 0xe3, 0x45, 125 | }) != 0 { 126 | t.Fail() 127 | } 128 | } 129 | 130 | func TestBehaviour(t *testing.T) { 131 | h := New(64) 132 | // Sum does not change the state 133 | hsh1 := h.Sum(nil) 134 | if bytes.Compare(h.Sum(nil), hsh1) != 0 { 135 | t.Fail() 136 | } 137 | // No data equals to no state changing 138 | h.Write([]byte{}) 139 | if bytes.Compare(h.Sum(nil), hsh1) != 0 { 140 | t.Fail() 141 | } 142 | // Just to be sure 143 | h.Write([]byte{}) 144 | if bytes.Compare(h.Sum(nil), hsh1) != 0 { 145 | t.Fail() 146 | } 147 | } 148 | 149 | func TestRandom(t *testing.T) { 150 | h := New(64) 151 | f := func(data []byte) bool { 152 | h.Reset() 153 | h.Write(data) 154 | d1 := h.Sum(nil) 155 | h.Reset() 156 | for _, c := range data { 157 | h.Write([]byte{c}) 158 | } 159 | d2 := h.Sum(nil) 160 | return bytes.Compare(d1, d2) == 0 161 | } 162 | if err := quick.Check(f, nil); err != nil { 163 | t.Error(err) 164 | } 165 | } 166 | 167 | func BenchmarkHash(b *testing.B) { 168 | h := New(64) 169 | src := make([]byte, BlockSize+1) 170 | rand.Read(src) 171 | b.ResetTimer() 172 | for i := 0; i < b.N; i++ { 173 | h.Write(src) 174 | h.Sum(nil) 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /internal/gost34112012/hmac_test.go: -------------------------------------------------------------------------------- 1 | // GoGOST -- Pure Go GOST cryptographic functions library 2 | // Copyright (C) 2015-2017 Sergey Matveev 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this program. If not, see 16 | // . 17 | 18 | package gost34112012 19 | 20 | import ( 21 | "bytes" 22 | "crypto/hmac" 23 | "hash" 24 | "testing" 25 | ) 26 | 27 | func hash256() hash.Hash { 28 | return New(32) 29 | } 30 | 31 | func hash512() hash.Hash { 32 | return New(64) 33 | } 34 | 35 | // HMAC test vectors taken from 36 | // http://tc26.ru/methods/recommendation/%D0%A2%D0%9A26%D0%90%D0%9B%D0%93.pdf test vectors 37 | func TestHMACVectors(t *testing.T) { 38 | h := hmac.New(hash256, []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}) 39 | h.Write([]byte{0x01, 0x26, 0xbd, 0xb8, 0x78, 0x00, 0xaf, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78, 0x01, 0x00}) 40 | if bytes.Compare(h.Sum(nil), []byte{0xa1, 0xaa, 0x5f, 0x7d, 0xe4, 0x02, 0xd7, 0xb3, 0xd3, 0x23, 0xf2, 0x99, 0x1c, 0x8d, 0x45, 0x34, 0x01, 0x31, 0x37, 0x01, 0x0a, 0x83, 0x75, 0x4f, 0xd0, 0xaf, 0x6d, 0x7c, 0xd4, 0x92, 0x2e, 0xd9}) != 0 { 41 | t.Fail() 42 | } 43 | 44 | h = hmac.New(hash512, []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}) 45 | h.Write([]byte{0x01, 0x26, 0xbd, 0xb8, 0x78, 0x00, 0xaf, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78, 0x01, 0x00}) 46 | if bytes.Compare(h.Sum(nil), []byte{0xa5, 0x9b, 0xab, 0x22, 0xec, 0xae, 0x19, 0xc6, 0x5f, 0xbd, 0xe6, 0xe5, 0xf4, 0xe9, 0xf5, 0xd8, 0x54, 0x9d, 0x31, 0xf0, 0x37, 0xf9, 0xdf, 0x9b, 0x90, 0x55, 0x00, 0xe1, 0x71, 0x92, 0x3a, 0x77, 0x3d, 0x5f, 0x15, 0x30, 0xf2, 0xed, 0x7e, 0x96, 0x4c, 0xb2, 0xee, 0xdc, 0x29, 0xe9, 0xad, 0x2f, 0x3a, 0xfe, 0x93, 0xb2, 0x81, 0x4f, 0x79, 0xf5, 0x00, 0x0f, 0xfc, 0x03, 0x66, 0xc2, 0x51, 0xe6}) != 0 { 47 | t.Fail() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /makedist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | cur=$(pwd) 4 | tmp=$(mktemp -d) 5 | release=$1 6 | [ -n "$release" ] 7 | 8 | git clone . $tmp/gogost-$release 9 | cd $tmp/gogost-$release 10 | git checkout $release 11 | git submodule update --init 12 | 13 | mkdir -p src/cypherpunks.ru/gogost/vendor 14 | cat > $tmp/includes <8 ------------------------ 53 | 54 | The main improvements for that release are: 55 | 56 | 57 | ------------------------ >8 ------------------------ 58 | 59 | GoGOST'es home page is: http://gogost.cypherpunks.ru/ 60 | Also available as I2P service: 61 | http://a5zmymxbjreuvbftgzmu64vcw2ssa3s44c2dn2jryxee6utn34qa.b32.i2p/ 62 | 63 | Source code and its signature for that version can be found here: 64 | 65 | http://gogost.cypherpunks.ru/gogost-${release}.tar.xz ($size KiB) 66 | http://gogost.cypherpunks.ru/gogost-${release}.tar.xz.sig 67 | 68 | Streebog-256 hash: $hashsb 69 | SHA256 hash: $hash 70 | GPG key: CEBD 1282 2C46 9C02 A81A 0467 8234 3436 696F C85A 71 | GoGOST releases 72 | 73 | Please send questions regarding the use of GoGOST, bug reports and patches 74 | to mailing list: https://lists.cypherpunks.ru/mailman/listinfo/gost 75 | EOF 76 | 77 | cat <8 ------------------------ 87 | 88 | Основные усовершенствования в этом релизе: 89 | 90 | 91 | ------------------------ >8 ------------------------ 92 | 93 | Домашняя страница GoGOST: http://gogost.cypherpunks.ru/ 94 | Также доступная как I2P сервис: 95 | http://a5zmymxbjreuvbftgzmu64vcw2ssa3s44c2dn2jryxee6utn34qa.b32.i2p/ 96 | 97 | Исходный код и его подпись для этой версии могут быть найдены здесь: 98 | 99 | http://gogost.cypherpunks.ru/gogost-${release}.tar.xz ($size KiB) 100 | http://gogost.cypherpunks.ru/gogost-${release}.tar.xz.sig 101 | 102 | Streebog-256 хэш: $hashsb 103 | SHA256 хэш: $hash 104 | GPG ключ: CEBD 1282 2C46 9C02 A81A 0467 8234 3436 696F C85A 105 | GoGOST releases 106 | 107 | Пожалуйста, все вопросы касающиеся использования GoGOST, отчёты об 108 | ошибках и патчи отправляйте в gost почтовую рассылку: 109 | https://lists.cypherpunks.ru/mailman/listinfo/gost 110 | EOF 111 | 112 | mv $tmp/$tarball $tmp/"$tarball".sig $cur/gogost.html/ 113 | -------------------------------------------------------------------------------- /www.mk: -------------------------------------------------------------------------------- 1 | all: gogost.html 2 | 3 | MAKEINFO ?= makeinfo 4 | 5 | gogost.html: www.texi 6 | rm -f gogost.html/*.html 7 | $(MAKEINFO) --html \ 8 | --set-customization-variable NO_CSS=1 \ 9 | --set-customization-variable SHOW_TITLE=0 \ 10 | --set-customization-variable USE_ACCESSKEY=0 \ 11 | --set-customization-variable DATE_IN_HEADER=1 \ 12 | --set-customization-variable TOP_NODE_UP_URL=index.html \ 13 | --set-customization-variable CLOSE_QUOTE_SYMBOL=\" \ 14 | --set-customization-variable OPEN_QUOTE_SYMBOL=\" \ 15 | -o gogost.html www.texi 16 | -------------------------------------------------------------------------------- /www.texi: -------------------------------------------------------------------------------- 1 | \input texinfo 2 | @documentencoding UTF-8 3 | @settitle GoGOST 4 | 5 | @copying 6 | Copyright @copyright{} 2015-2017 @email{stargrave@@stargrave.org, Sergey Matveev} 7 | @end copying 8 | 9 | @node Top 10 | @top GoGOST 11 | 12 | Pure Go GOST cryptographic functions library. 13 | GOST is GOvernment STandard of Russian Federation (and Soviet Union). 14 | It is 15 | @url{https://www.gnu.org/philosophy/pragmatic.html, copylefted} 16 | @url{https://www.gnu.org/philosophy/free-sw.html, free software}: 17 | licenced under @url{https://www.gnu.org/licenses/lgpl.html, GNU LGPLv3+}. 18 | You can read about GOST algorithms @url{http://gost.cypherpunks.ru/, more}. 19 | 20 | Site is also available as @url{http://a5zmymxbjreuvbftgzmu64vcw2ssa3s44c2dn2jryxee6utn34qa.b32.i2p/, I2P service}. 21 | 22 | Currently supported algorithms are: 23 | 24 | @itemize 25 | @item GOST 28147-89 (@url{https://tools.ietf.org/html/rfc5830.html, RFC 5830}) 26 | block cipher with ECB, CNT (CTR), CFB, MAC, 27 | CBC (@url{https://tools.ietf.org/html/rfc4357.html, RFC 4357}) 28 | modes of operation 29 | @item various 28147-89-related S-boxes included 30 | @item GOST R 34.11-94 hash function 31 | (@url{https://tools.ietf.org/html/rfc5831.html, RFC 5831}) 32 | @item GOST R 34.11-2012 Стрибог (Streebog) hash function 33 | (@url{https://tools.ietf.org/html/rfc6986.html, RFC 6986}) 34 | @item GOST R 34.10-2001 35 | (@url{https://tools.ietf.org/html/rfc5832.html, RFC 5832}) 36 | public key signature function 37 | @item GOST R 34.10-2012 38 | (@url{https://tools.ietf.org/html/rfc7091.html, RFC 7091}) 39 | public key signature function 40 | @item various 34.10 curve parameters included 41 | @item VKO GOST R 34.10-2001 key agreement function 42 | (@url{https://tools.ietf.org/html/rfc4357.html, RFC 4357}) 43 | @item VKO GOST R 34.10-2012 key agreement function 44 | (@url{https://tools.ietf.org/html/rfc7836.html, RFC 7836}) 45 | @item GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) 46 | (@url{https://tools.ietf.org/html/rfc7801.html, RFC 7801}) 47 | @item GOST R 34.13-2015 padding methods 48 | @end itemize 49 | 50 | Please send questions, bug reports and patches to 51 | @url{https://lists.cypherpunks.ru/mailman/listinfo/gost, gost} 52 | mailing list. Announcements also go to this mailing list. 53 | 54 | @insertcopying 55 | 56 | @node News 57 | @unnumbered News 58 | 59 | @table @strong 60 | 61 | @item 2.1 62 | Licence changed from GNU GPLv3+ to GNU LGPLv3+. 63 | 64 | @item 2.0 65 | @itemize 66 | @item 34.11-2012 is split on two different modules: 67 | @code{gost34112012256} and @code{gost34112012512} 68 | @item 34.11-94's digest is reversed. Now it is compatible with TC26's 69 | HMAC and PBKDF2 test vectors 70 | @item @code{gogost-streebog} is split to @code{streebog256} and 71 | @code{streebog512} correspondingly by analogy with sha* utilities 72 | @item added VKO 34.10-2012 support with corresponding test vectors 73 | @item @code{gost3410.DigestSizeX} is renamed to 74 | @code{gost3410.ModeX} because it is not related to digest size, 75 | but parameters and key sizes 76 | @item KEK functions take @code{big.Int} UKM value. Use @code{NewUKM} 77 | to unmarshal raw binary UKM 78 | @end itemize 79 | 80 | @item 1.1 81 | @itemize 82 | @item gogost-streebog is able to use either 256 or 512 bits digest size 83 | @item 34.13-2015 padding methods 84 | @item 28147-89 CBC mode of operation 85 | @end itemize 86 | 87 | @end table 88 | 89 | @node Download 90 | @unnumbered Download 91 | 92 | Preferable way is to download tarball with the signature from 93 | website and, for example, run tests with benchmarks: 94 | 95 | @verbatim 96 | % wget http://gogost.cypherpunks.ru/gogost-1.1.tar.xz 97 | % wget http://gogost.cypherpunks.ru/gogost-1.1.tar.xz.sig 98 | % gpg --verify gogost-1.1.tar.xz.sig gogost-1.1.tar.xz 99 | % xz -d < gogost-1.1.tar.xz | tar xf - 100 | % make -C gogost-1.1 all bench 101 | % echo hello world | ./gogost-1.1/streebog256 102 | f72018189a5cfb803dbe1f2149cf554c40093d8e7f81c21e08ac5bcd09d9934d 103 | @end verbatim 104 | 105 | And then you can include its source code in your project for example 106 | like this: 107 | 108 | @verbatim 109 | % mkdir -p myproj/src 110 | % export GOPATH=$PWD/myproj 111 | % cd myproj/src 112 | % cat > main.go < 171 | @end verbatim 172 | 173 | @itemize 174 | 175 | @item @url{https://lists.cypherpunks.ru/mailman/listinfo/gost, gost} maillist 176 | 177 | @item 178 | @verbatim 179 | % gpg --keyserver hkp://keys.gnupg.net/ --recv-keys 0x82343436696FC85A 180 | % gpg --auto-key-locate dane --locate-keys gogost at cypherpunks dot ru 181 | % gpg --auto-key-locate wkd --locate-keys gogost at cypherpunks dot ru 182 | % gpg --auto-key-locate pka --locate-keys gogost at cypherpunks dot ru 183 | @end verbatim 184 | 185 | @item 186 | @verbatiminclude PUBKEY.asc 187 | 188 | @end itemize 189 | 190 | You can obtain development source code by cloning 191 | @url{http://git-scm.com/, Git} 192 | @url{https://git.cypherpunks.ru/cgit.cgi/gogost.git/}. 193 | 194 | @bye 195 | --------------------------------------------------------------------------------