From 16dfff064cc12e9a7d91ccd2f81c3ff2d5b68d53 Mon Sep 17 00:00:00 2001 From: Aron Wussler Date: Wed, 25 Jan 2023 13:28:19 +0100 Subject: [PATCH] Drop support for MD5, RIPEMD160, deprecate SHA1, CAST5, 3DES --- openpgp/clearsign/clearsign.go | 10 --- openpgp/internal/algorithm/hash.go | 67 ++++++++++++++++--- openpgp/key_generation.go | 7 +- openpgp/keys_test.go | 7 ++ openpgp/packet/encrypted_key.go | 8 ++- openpgp/packet/one_pass_signature.go | 6 +- openpgp/packet/packet.go | 10 +++ openpgp/packet/private_key.go | 3 + openpgp/packet/signature.go | 28 ++++++-- openpgp/packet/symmetric_key_encrypted.go | 15 ++--- .../packet/symmetric_key_encrypted_test.go | 2 - .../packet/symmetrically_encrypted_aead.go | 6 +- openpgp/packet/symmetrically_encrypted_mdc.go | 12 ++-- openpgp/read.go | 13 ++-- openpgp/read_write_test_data.go | 2 +- openpgp/s2k/s2k.go | 32 +-------- openpgp/s2k/s2k_test.go | 2 +- openpgp/write.go | 20 +++--- 18 files changed, 157 insertions(+), 93 deletions(-) diff --git a/openpgp/clearsign/clearsign.go b/openpgp/clearsign/clearsign.go index 9f695623c..80029814e 100644 --- a/openpgp/clearsign/clearsign.go +++ b/openpgp/clearsign/clearsign.go @@ -421,12 +421,6 @@ func (b *Block) VerifySignature(keyring openpgp.KeyRing, config *packet.Config) // if the name isn't known. See RFC 4880, section 9.4. func nameOfHash(h crypto.Hash) string { switch h { - case crypto.MD5: - return "MD5" - case crypto.SHA1: - return "SHA1" - case crypto.RIPEMD160: - return "RIPEMD160" case crypto.SHA224: return "SHA224" case crypto.SHA256: @@ -447,12 +441,8 @@ func nameOfHash(h crypto.Hash) string { // if the name isn't known. See RFC 4880, section 9.4. func nameToHash(h string) crypto.Hash { switch h { - case "MD5": - return crypto.MD5 case "SHA1": return crypto.SHA1 - case "RIPEMD160": - return crypto.RIPEMD160 case "SHA224": return crypto.SHA224 case "SHA256": diff --git a/openpgp/internal/algorithm/hash.go b/openpgp/internal/algorithm/hash.go index f0a1815fb..82e43d674 100644 --- a/openpgp/internal/algorithm/hash.go +++ b/openpgp/internal/algorithm/hash.go @@ -32,9 +32,7 @@ type Hash interface { // The following vars mirror the crypto/Hash supported hash functions. var ( - MD5 Hash = cryptoHash{1, crypto.MD5} SHA1 Hash = cryptoHash{2, crypto.SHA1} - RIPEMD160 Hash = cryptoHash{3, crypto.RIPEMD160} SHA256 Hash = cryptoHash{8, crypto.SHA256} SHA384 Hash = cryptoHash{9, crypto.SHA384} SHA512 Hash = cryptoHash{10, crypto.SHA512} @@ -47,9 +45,6 @@ var ( // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-14 var ( HashById = map[uint8]Hash{ - MD5.Id(): MD5, - SHA1.Id(): SHA1, - RIPEMD160.Id(): RIPEMD160, SHA256.Id(): SHA256, SHA384.Id(): SHA384, SHA512.Id(): SHA512, @@ -72,9 +67,6 @@ func (h cryptoHash) Id() uint8 { } var hashNames = map[uint8]string{ - MD5.Id(): "MD5", - SHA1.Id(): "SHA1", - RIPEMD160.Id(): "RIPEMD160", SHA256.Id(): "SHA256", SHA384.Id(): "SHA384", SHA512.Id(): "SHA512", @@ -90,3 +82,62 @@ func (h cryptoHash) String() string { } return s } + +// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP +// hash id. +func HashIdToHash(id byte) (h crypto.Hash, ok bool) { + if hash, ok := HashById[id]; ok { + return hash.HashFunc(), true + } + return 0, false +} + +// HashIdToHashWithSha1 returns a crypto.Hash which corresponds to the given OpenPGP +// hash id, allowing sha1. +func HashIdToHashWithSha1(id byte) (h crypto.Hash, ok bool) { + if hash, ok := HashById[id]; ok { + return hash.HashFunc(), true + } + + if id == SHA1.Id() { + return SHA1.HashFunc(), true + } + + return 0, false +} + +// HashIdToString returns the name of the hash function corresponding to the +// given OpenPGP hash id. +func HashIdToString(id byte) (name string, ok bool) { + if hash, ok := HashById[id]; ok { + return hash.String(), true + } + return "", false +} + +// HashToHashId returns an OpenPGP hash id which corresponds the given Hash. +func HashToHashId(h crypto.Hash) (id byte, ok bool) { + for id, hash := range HashById { + if hash.HashFunc() == h { + return id, true + } + } + + return 0, false +} + +// HashToHashIdWithSha1 returns an OpenPGP hash id which corresponds the given Hash, +// allowing instances of SHA1 +func HashToHashIdWithSha1(h crypto.Hash) (id byte, ok bool) { + for id, hash := range HashById { + if hash.HashFunc() == h { + return id, true + } + } + + if h == SHA1.HashFunc() { + return SHA1.Id(), true + } + + return 0, false +} diff --git a/openpgp/key_generation.go b/openpgp/key_generation.go index 5fbfe8388..77012fe1f 100644 --- a/openpgp/key_generation.go +++ b/openpgp/key_generation.go @@ -101,7 +101,12 @@ func (t *Entity) addUserId(name, comment, email string, config *packet.Config, c // Set the PreferredHash for the SelfSignature from the packet.Config. // If it is not the must-implement algorithm from rfc4880bis, append that. - selfSignature.PreferredHash = []uint8{hashToHashId(config.Hash())} + hash, ok := algorithm.HashToHashId(config.Hash()) + if !ok { + return errors.UnsupportedError("unsupported preferred hash function") + } + + selfSignature.PreferredHash = []uint8{hash} if config.Hash() != crypto.SHA256 { selfSignature.PreferredHash = append(selfSignature.PreferredHash, hashToHashId(crypto.SHA256)) } diff --git a/openpgp/keys_test.go b/openpgp/keys_test.go index 031dea685..35595e6b0 100644 --- a/openpgp/keys_test.go +++ b/openpgp/keys_test.go @@ -802,6 +802,13 @@ func TestNewEntityWithDefaultHash(t *testing.T) { DefaultHash: hash, } entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", c) + if hash == crypto.SHA1 { + if err == nil { + t.Fatal("should fail on SHA1 key creation") + } + continue + } + if err != nil { t.Fatal(err) } diff --git a/openpgp/packet/encrypted_key.go b/openpgp/packet/encrypted_key.go index 58ebe1cc7..90ec27966 100644 --- a/openpgp/packet/encrypted_key.go +++ b/openpgp/packet/encrypted_key.go @@ -25,7 +25,7 @@ const encryptedKeyVersion = 3 type EncryptedKey struct { KeyId uint64 Algo PublicKeyAlgorithm - CipherFunc CipherFunction // only valid after a successful Decrypt for a v4 packet + CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet Key []byte // only valid after a successful Decrypt encryptedMPI1, encryptedMPI2 encoding.Field @@ -123,6 +123,10 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { } e.CipherFunc = CipherFunction(b[0]) + if !e.CipherFunc.IsSupported() { + return errors.UnsupportedError("unsupported encryption function") + } + e.Key = b[1 : len(b)-2] expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) checksum := checksumKeyMaterial(e.Key) @@ -279,4 +283,4 @@ func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub } _, err = w.Write(m.EncodedBytes()) return err -} +} \ No newline at end of file diff --git a/openpgp/packet/one_pass_signature.go b/openpgp/packet/one_pass_signature.go index 41c35de21..fff119e63 100644 --- a/openpgp/packet/one_pass_signature.go +++ b/openpgp/packet/one_pass_signature.go @@ -8,7 +8,7 @@ import ( "crypto" "encoding/binary" "github.com/ProtonMail/go-crypto/openpgp/errors" - "github.com/ProtonMail/go-crypto/openpgp/s2k" + "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "io" "strconv" ) @@ -37,7 +37,7 @@ func (ops *OnePassSignature) parse(r io.Reader) (err error) { } var ok bool - ops.Hash, ok = s2k.HashIdToHash(buf[2]) + ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2]) if !ok { return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2]))) } @@ -55,7 +55,7 @@ func (ops *OnePassSignature) Serialize(w io.Writer) error { buf[0] = onePassSignatureVersion buf[1] = uint8(ops.SigType) var ok bool - buf[2], ok = s2k.HashToHashId(ops.Hash) + buf[2], ok = algorithm.HashToHashId(ops.Hash) if !ok { return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) } diff --git a/openpgp/packet/packet.go b/openpgp/packet/packet.go index d7d4bb3f4..9fe788f01 100644 --- a/openpgp/packet/packet.go +++ b/openpgp/packet/packet.go @@ -455,6 +455,16 @@ func (cipher CipherFunction) KeySize() int { return algorithm.CipherFunction(cipher).KeySize() } +// IsSupported returns true if the cipher is supported from the library +func (cipher CipherFunction) IsSupported() bool { + return algorithm.CipherFunction(cipher).KeySize() > 0 +} + +// IsAes returns true if the cipher is AES +func (cipher CipherFunction) IsAes() bool { + return cipher.IsSupported() && cipher >= CipherAES128 +} + // blockSize returns the block size, in bytes, of cipher. func (cipher CipherFunction) blockSize() int { return algorithm.CipherFunction(cipher).BlockSize() diff --git a/openpgp/packet/private_key.go b/openpgp/packet/private_key.go index 009f0ef1d..921a4dda8 100644 --- a/openpgp/packet/private_key.go +++ b/openpgp/packet/private_key.go @@ -179,6 +179,9 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) { return } pk.cipher = CipherFunction(buf[0]) + if !pk.cipher.IsSupported() { + return errors.UnsupportedError("unsupported cipher function in private key") + } pk.s2kParams, err = s2k.ParseIntoParams(r) if err != nil { return diff --git a/openpgp/packet/signature.go b/openpgp/packet/signature.go index a37352d91..e653d74ca 100644 --- a/openpgp/packet/signature.go +++ b/openpgp/packet/signature.go @@ -9,6 +9,7 @@ import ( "crypto" "crypto/dsa" "encoding/binary" + "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "hash" "io" "strconv" @@ -18,7 +19,6 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/eddsa" "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/internal/encoding" - "github.com/ProtonMail/go-crypto/openpgp/s2k" ) const ( @@ -138,7 +138,13 @@ func (sig *Signature) parse(r io.Reader) (err error) { } var ok bool - sig.Hash, ok = s2k.HashIdToHash(buf[2]) + + if sig.Version < 5 { + sig.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2]) + } else { + sig.Hash, ok = algorithm.HashIdToHash(buf[2]) + } + if !ok { return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) } @@ -149,7 +155,11 @@ func (sig *Signature) parse(r io.Reader) (err error) { if err != nil { return } - sig.buildHashSuffix(hashedSubpackets) + err = sig.buildHashSuffix(hashedSubpackets) + if err != nil { + return + } + err = parseSignatureSubpackets(sig, hashedSubpackets, true) if err != nil { return @@ -597,7 +607,15 @@ func (sig *Signature) SigExpired(currentTime time.Time) bool { // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. func (sig *Signature) buildHashSuffix(hashedSubpackets []byte) (err error) { - hash, ok := s2k.HashToHashId(sig.Hash) + var hashId byte + var ok bool + + if sig.Version < 5 { + hashId, ok = algorithm.HashToHashIdWithSha1(sig.Hash) + } else { + hashId, ok = algorithm.HashToHashId(sig.Hash) + } + if !ok { sig.HashSuffix = nil return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) @@ -607,7 +625,7 @@ func (sig *Signature) buildHashSuffix(hashedSubpackets []byte) (err error) { uint8(sig.Version), uint8(sig.SigType), uint8(sig.PubKeyAlgo), - uint8(hash), + uint8(hashId), uint8(len(hashedSubpackets) >> 8), uint8(len(hashedSubpackets)), }) diff --git a/openpgp/packet/symmetric_key_encrypted.go b/openpgp/packet/symmetric_key_encrypted.go index 19f60f5f3..2f3f085ff 100644 --- a/openpgp/packet/symmetric_key_encrypted.go +++ b/openpgp/packet/symmetric_key_encrypted.go @@ -57,7 +57,7 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { return err } ske.CipherFunc = CipherFunction(buf[0]) - if ske.CipherFunc.KeySize() == 0 { + if !ske.CipherFunc.IsSupported() { return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[0]))) } @@ -168,12 +168,11 @@ func (ske *SymmetricKeyEncrypted) decryptV5(key []byte) ([]byte, error) { // If config is nil, sensible defaults will be used. func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { cipherFunc := config.Cipher() - keySize := cipherFunc.KeySize() - if keySize == 0 { - return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) + if !cipherFunc.IsAes() { + return nil, errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(cipherFunc))) } - sessionKey := make([]byte, keySize) + sessionKey := make([]byte, cipherFunc.KeySize()) _, err = io.ReadFull(config.Random(), sessionKey) if err != nil { return @@ -201,11 +200,11 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass version = 4 } cipherFunc := config.Cipher() - keySize := cipherFunc.KeySize() - if keySize == 0 { - return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) + if !cipherFunc.IsAes() { + return errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(cipherFunc))) } + keySize := cipherFunc.KeySize() s2kBuf := new(bytes.Buffer) keyEncryptingKey := make([]byte, keySize) // s2k.Serialize salts and stretches the passphrase, and writes the diff --git a/openpgp/packet/symmetric_key_encrypted_test.go b/openpgp/packet/symmetric_key_encrypted_test.go index ca451ed16..8d6e4c356 100644 --- a/openpgp/packet/symmetric_key_encrypted_test.go +++ b/openpgp/packet/symmetric_key_encrypted_test.go @@ -115,8 +115,6 @@ func TestSerializeSymmetricKeyEncryptedV5RandomizeSlow(t *testing.T) { func TestSerializeSymmetricKeyEncryptedCiphersV4(t *testing.T) { tests := map[string] CipherFunction { - "3DES": Cipher3DES, - "CAST5": CipherCAST5, "AES128": CipherAES128, "AES192": CipherAES192, "AES256": CipherAES256, diff --git a/openpgp/packet/symmetrically_encrypted_aead.go b/openpgp/packet/symmetrically_encrypted_aead.go index 7805c7830..58eda2468 100644 --- a/openpgp/packet/symmetrically_encrypted_aead.go +++ b/openpgp/packet/symmetrically_encrypted_aead.go @@ -22,7 +22,7 @@ func (se *SymmetricallyEncrypted) parseAead(r io.Reader) error { // Cipher se.cipher = CipherFunction(headerData[0]) - if se.cipher.KeySize() == 0 { + if !se.cipher.IsAes() { return errors.UnsupportedError("unknown cipher: " + string(se.cipher)) } @@ -87,6 +87,10 @@ func (se *SymmetricallyEncrypted) decryptAead(inputKey []byte) (io.ReadCloser, e // serializeSymmetricallyEncryptedAead encrypts to a writer a V2 SEIPD packet (AEAD) as specified in // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2 func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite CipherSuite, chunkSizeByte byte, rand io.Reader, inputKey []byte) (Contents io.WriteCloser, err error) { + if !cipherSuite.Cipher.IsAes() { + return nil, errors.InvalidArgumentError("invalid aead cipher function") + } + if cipherSuite.Cipher.KeySize() != len(inputKey) { return nil, errors.InvalidArgumentError("error in aead serialization: bad key length") } diff --git a/openpgp/packet/symmetrically_encrypted_mdc.go b/openpgp/packet/symmetrically_encrypted_mdc.go index 78c77e42a..93a9aedc7 100644 --- a/openpgp/packet/symmetrically_encrypted_mdc.go +++ b/openpgp/packet/symmetrically_encrypted_mdc.go @@ -29,11 +29,11 @@ func (ser seMdcReader) Close() error { } func (se *SymmetricallyEncrypted) decryptMdc(c CipherFunction, key []byte) (io.ReadCloser, error) { - keySize := c.KeySize() - if keySize == 0 { - return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) + if !c.IsSupported() { + return nil, errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(c))) } - if len(key) != keySize { + + if len(key) != c.KeySize() { return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") } @@ -220,6 +220,10 @@ func (c noOpCloser) Close() error { } func serializeSymmetricallyEncryptedMdc(ciphertext io.WriteCloser, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) { + if !c.IsAes() { + return nil, errors.InvalidArgumentError("invalid mdc cipher function") + } + if c.KeySize() != len(key) { return nil, errors.InvalidArgumentError("error in mdc serialization: bad key length") } diff --git a/openpgp/read.go b/openpgp/read.go index c7ac829dc..bfe5f6ff0 100644 --- a/openpgp/read.go +++ b/openpgp/read.go @@ -9,6 +9,7 @@ import ( "crypto" _ "crypto/sha256" _ "crypto/sha512" + "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "hash" "io" "strconv" @@ -304,14 +305,14 @@ FindLiteralData: // should be preprocessed (i.e. to normalize line endings). Thus this function // returns two hashes. The second should be used to hash the message itself and // performs any needed preprocessing. -func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { - if hashId == crypto.MD5 { - return nil, nil, errors.UnsupportedError("insecure hash algorithm: MD5") +func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { + if _, ok := algorithm.HashToHashIdWithSha1(hashFunc); !ok { + return nil, nil, errors.UnsupportedError("unsupported hash function") } - if !hashId.Available() { - return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) + if !hashFunc.Available() { + return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashFunc))) } - h := hashId.New() + h := hashFunc.New() switch sigType { case packet.SigTypeBinary: diff --git a/openpgp/read_write_test_data.go b/openpgp/read_write_test_data.go index 117a14643..d2ba22c97 100644 --- a/openpgp/read_write_test_data.go +++ b/openpgp/read_write_test_data.go @@ -106,7 +106,7 @@ const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6 const rsaSignatureBadMPIlength = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101` -const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101` +const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101` const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000` diff --git a/openpgp/s2k/s2k.go b/openpgp/s2k/s2k.go index 8862c7c2e..d0b858345 100644 --- a/openpgp/s2k/s2k.go +++ b/openpgp/s2k/s2k.go @@ -172,7 +172,7 @@ func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { // Generate generates valid parameters from given configuration. // It will enforce salted + hashed s2k method func Generate(rand io.Reader, c *Config) (*Params, error) { - hashId, ok := HashToHashId(c.Hash) + hashId, ok := algorithm.HashToHashId(c.Hash) if !ok { return nil, errors.UnsupportedError("no such hash") } @@ -262,7 +262,7 @@ func (params *Params) Function() (f func(out, in []byte), err error) { if params.Dummy() { return nil, errors.ErrDummyPrivateKey("dummy key found") } - hashObj, ok := HashIdToHash(params.hashId) + hashObj, ok := algorithm.HashIdToHashWithSha1(params.hashId) if !ok { return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(params.hashId))) } @@ -337,31 +337,3 @@ func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Co f(key, passphrase) return nil } - -// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP -// hash id. -func HashIdToHash(id byte) (h crypto.Hash, ok bool) { - if hash, ok := algorithm.HashById[id]; ok { - return hash.HashFunc(), true - } - return 0, false -} - -// HashIdToString returns the name of the hash function corresponding to the -// given OpenPGP hash id. -func HashIdToString(id byte) (name string, ok bool) { - if hash, ok := algorithm.HashById[id]; ok { - return hash.String(), true - } - return "", false -} - -// HashToHashId returns an OpenPGP hash id which corresponds the given Hash. -func HashToHashId(h crypto.Hash) (id byte, ok bool) { - for id, hash := range algorithm.HashById { - if hash.HashFunc() == h { - return id, true - } - } - return 0, false -} diff --git a/openpgp/s2k/s2k_test.go b/openpgp/s2k/s2k_test.go index c4be8bcbe..10071173f 100644 --- a/openpgp/s2k/s2k_test.go +++ b/openpgp/s2k/s2k_test.go @@ -138,7 +138,7 @@ func TestParseIntoParams(t *testing.T) { func TestSerializeOK(t *testing.T) { hashes := []crypto.Hash{crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA224, crypto.SHA3_256, - crypto.SHA3_512, crypto.SHA1, crypto.RIPEMD160} + crypto.SHA3_512} testCounts := []int{-1, 0, 1024, 65536, 4063232, 65011712} for _, h := range hashes { for _, c := range testCounts { diff --git a/openpgp/write.go b/openpgp/write.go index 3a4f37e5c..9cc666276 100644 --- a/openpgp/write.go +++ b/openpgp/write.go @@ -6,6 +6,7 @@ package openpgp import ( "crypto" + "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "hash" "io" "strconv" @@ -14,7 +15,6 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/packet" - "github.com/ProtonMail/go-crypto/openpgp/s2k" ) // DetachSign signs message with the private key from signer (which must @@ -70,6 +70,9 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S if signingKey.PrivateKey.Encrypted { return errors.InvalidArgumentError("signing key is encrypted") } + if _, ok := algorithm.HashToHashId(config.Hash()); !ok { + return errors.InvalidArgumentError("invalid hash function") + } sig := new(packet.Signature) sig.SigType = sigType @@ -188,7 +191,7 @@ func intersectCipherSuites(a [][2]uint8, b [][2]uint8) (intersection [][2]uint8) } func hashToHashId(h crypto.Hash) uint8 { - v, ok := s2k.HashToHashId(h) + v, ok := algorithm.HashToHashId(h) if !ok { panic("tried to convert unknown hash") } @@ -254,7 +257,7 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit var hash crypto.Hash for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { + if h, ok := algorithm.HashIdToHash(hashId); ok && h.Available() { hash = h break } @@ -263,7 +266,7 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit // If the hash specified by config is a candidate, we'll use that. if configuredHash := config.Hash(); configuredHash.Available() { for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { + if h, ok := algorithm.HashIdToHash(hashId); ok && h == configuredHash { hash = h break } @@ -272,7 +275,7 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit if hash == 0 { hashId := candidateHashes[0] - name, ok := s2k.HashIdToString(hashId) + name, ok := algorithm.HashIdToString(hashId) if !ok { name = "#" + strconv.Itoa(int(hashId)) } @@ -343,9 +346,8 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En // These are the possible ciphers that we'll use for the message. candidateCiphers := []uint8{ - uint8(packet.CipherAES128), uint8(packet.CipherAES256), - uint8(packet.CipherCAST5), + uint8(packet.CipherAES128), } // These are the possible hash functions that we'll use for the signature. @@ -355,8 +357,6 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En hashToHashId(crypto.SHA512), hashToHashId(crypto.SHA3_256), hashToHashId(crypto.SHA3_512), - hashToHashId(crypto.SHA1), - hashToHashId(crypto.RIPEMD160), } // Prefer GCM if everyone supports it @@ -470,8 +470,6 @@ func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Con hashToHashId(crypto.SHA512), hashToHashId(crypto.SHA3_256), hashToHashId(crypto.SHA3_512), - hashToHashId(crypto.SHA1), - hashToHashId(crypto.RIPEMD160), } defaultHashes := candidateHashes[0:1] preferredHashes := signed.PrimaryIdentity().SelfSignature.PreferredHash