From 020529d442498b336adf52d56b4602da1e4c4147 Mon Sep 17 00:00:00 2001 From: Aron Wussler Date: Wed, 22 May 2024 21:35:30 +0200 Subject: [PATCH] Update KDF to use SHA3-256 --- internal/kmac/kmac.go | 144 --------------------------- internal/kmac/kmac_test.go | 130 ------------------------- openpgp/mlkem_ecdh/mlkem_ecdh.go | 26 +++-- openpgp/pqc_vectors_test.go | 141 +++++++++++++++------------ openpgp/read_write_test_data.go | 162 +++++++++++++++---------------- 5 files changed, 175 insertions(+), 428 deletions(-) delete mode 100644 internal/kmac/kmac.go delete mode 100644 internal/kmac/kmac_test.go diff --git a/internal/kmac/kmac.go b/internal/kmac/kmac.go deleted file mode 100644 index 6098446e6..000000000 --- a/internal/kmac/kmac.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package kmac provides function for creating KMAC instances. -// KMAC is a Message Authentication Code that based on SHA-3 and -// specified in NIST Special Publication 800-185, "SHA-3 Derived Functions: -// cSHAKE, KMAC, TupleHash and ParallelHash" [1] -// -// [1] https://doi.org/10.6028/NIST.SP.800-185 -package kmac - -import ( - "encoding/binary" - "golang.org/x/crypto/sha3" - "hash" -) - -const ( - // According to [1]: - // "When used as a MAC, applications of this Recommendation shall - // not select an output length L that is less than 32 bits, and - // shall only select an output length less than 64 bits after a - // careful risk analysis is performed." - // 64 bits was selected for safety. - kmacMinimumTagSize = 8 - rate128 = 168 - rate256 = 136 -) - -// KMAC specific context -type kmac struct { - sha3.ShakeHash // cSHAKE context and Read/Write operations - tagSize int // tag size - // initBlock is the KMAC specific initialization set of bytes. It is initialized - // by newKMAC function and stores the key, encoded by the method specified in 3.3 of [1]. - // It is stored here in order for Reset() to be able to put context into - // initial state. - initBlock []byte - rate int -} - -// NewKMAC128 returns a new KMAC hash providing 128 bits of security using -// the given key, which must have 16 bytes or more, generating the given tagSize -// bytes output and using the given customizationString. -// Note that unlike other hash implementations in the standard library, -// the returned Hash does not implement encoding.BinaryMarshaler -// or encoding.BinaryUnmarshaler. -func NewKMAC128(key []byte, tagSize int, customizationString []byte) hash.Hash { - if len(key) < 16 { - panic("Key must not be smaller than security strength") - } - c := sha3.NewCShake128([]byte("KMAC"), customizationString) - return newKMAC(key, tagSize, c, rate128) -} - -// NewKMAC256 returns a new KMAC hash providing 256 bits of security using -// the given key, which must have 32 bytes or more, generating the given tagSize -// bytes output and using the given customizationString. -// Note that unlike other hash implementations in the standard library, -// the returned Hash does not implement encoding.BinaryMarshaler -// or encoding.BinaryUnmarshaler. - -func NewKMAC256(key []byte, tagSize int, customizationString []byte) hash.Hash { - if len(key) < 32 { - panic("Key must not be smaller than security strength") - } - c := sha3.NewCShake256([]byte("KMAC"), customizationString) - return newKMAC(key, tagSize, c, rate256) -} - -func newKMAC(key []byte, tagSize int, c sha3.ShakeHash, rate int) hash.Hash { - if tagSize < kmacMinimumTagSize { - panic("tagSize is too small") - } - k := &kmac{ShakeHash: c, tagSize: tagSize, rate: rate} - // leftEncode returns max 9 bytes - k.initBlock = make([]byte, 0, 9+len(key)) - k.initBlock = append(k.initBlock, leftEncode(uint64(len(key)*8))...) - k.initBlock = append(k.initBlock, key...) - k.Write(bytepad(k.initBlock, k.BlockSize())) - return k -} - -// Reset resets the hash to initial state. -func (k *kmac) Reset() { - k.ShakeHash.Reset() - k.Write(bytepad(k.initBlock, k.BlockSize())) -} - -// BlockSize returns the hash block size. -func (k *kmac) BlockSize() int { - return k.rate -} - -// Size returns the tag size. -func (k *kmac) Size() int { - return k.tagSize -} - -// Sum appends the current KMAC to b and returns the resulting slice. -// It does not change the underlying hash state. -func (k *kmac) Sum(b []byte) []byte { - dup := k.ShakeHash.Clone() - dup.Write(rightEncode(uint64(k.tagSize * 8))) - hash := make([]byte, k.tagSize) - dup.Read(hash) - return append(b, hash...) -} - -func bytepad(input []byte, w int) []byte { - // leftEncode always returns max 9 bytes - buf := make([]byte, 0, 9+len(input)+w) - buf = append(buf, leftEncode(uint64(w))...) - buf = append(buf, input...) - padlen := w - (len(buf) % w) - return append(buf, make([]byte, padlen)...) -} - -func leftEncode(value uint64) []byte { - var b [9]byte - binary.BigEndian.PutUint64(b[1:], value) - // Trim all but last leading zero bytes - i := byte(1) - for i < 8 && b[i] == 0 { - i++ - } - // Prepend number of encoded bytes - b[i-1] = 9 - i - return b[i-1:] -} - -func rightEncode(value uint64) []byte { - var b [9]byte - binary.BigEndian.PutUint64(b[:8], value) - // Trim all but last leading zero bytes - i := byte(0) - for i < 7 && b[i] == 0 { - i++ - } - // Append number of encoded bytes - b[8] = 8 - i - return b[i:] -} diff --git a/internal/kmac/kmac_test.go b/internal/kmac/kmac_test.go deleted file mode 100644 index 1b6902353..000000000 --- a/internal/kmac/kmac_test.go +++ /dev/null @@ -1,130 +0,0 @@ -/// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package kmac_test implements a vector-based test suite for the cSHAKE KMAC implementation -package kmac_test - -import ( - "bytes" - "encoding/hex" - "fmt" - "github.com/ProtonMail/go-crypto/internal/kmac" - "hash" - "testing" -) -// Test vectors from -// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf -var kmacTests = []struct { - security int - key, data, customization, tag string -}{ - { - 128, - "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", - "00010203", - "", - "E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E", - }, - { - 128, - "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", - "00010203", - "My Tagged Application", - "3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5", - }, - { - 128, - "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", - "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7", - "My Tagged Application", - "1F5B4E6CCA02209E0DCB5CA635B89A15E271ECC760071DFD805FAA38F9729230", - }, - { - 256, - "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", - "00010203", - "My Tagged Application", - "20C570C31346F703C9AC36C61C03CB64C3970D0CFC787E9B79599D273A68D2F7F69D4CC3DE9D104A351689F27CF6F5951F0103F33F4F24871024D9C27773A8DD", - }, - { - 256, - "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", - "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7", - "", - "75358CF39E41494E949707927CEE0AF20A3FF553904C86B08F21CC414BCFD691589D27CF5E15369CBBFF8B9A4C2EB17800855D0235FF635DA82533EC6B759B69", - }, - { - 256, - "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", - "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7", - "My Tagged Application", - "B58618F71F92E1D56C1B8C55DDD7CD188B97B4CA4D99831EB2699A837DA2E4D970FBACFDE50033AEA585F1A2708510C32D07880801BD182898FE476876FC8965", - }, -} -func TestKMAC(t *testing.T) { - for i, test := range kmacTests { - key, err := hex.DecodeString(test.key) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - tag, err := hex.DecodeString(test.tag) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - var mac hash.Hash - if test.security == 128 { - mac = kmac.NewKMAC128(key, len(tag), []byte(test.customization)) - } else { - mac = kmac.NewKMAC256(key, len(tag), []byte(test.customization)) - } - data, err := hex.DecodeString(test.data) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - mac.Write(data) - computedTag := mac.Sum(nil) - if !bytes.Equal(tag, computedTag) { - t.Errorf("#%d: got %x, want %x", i, tag, computedTag) - } - if mac.Size() != len(tag) { - t.Errorf("#%d: Size() = %x, want %x", i, mac.Size(), len(tag)) - } - // Test if it works after Reset. - mac.Reset() - mac.Write(data) - computedTag = mac.Sum(nil) - if !bytes.Equal(tag, computedTag) { - t.Errorf("#%d: got %x, want %x", i, tag, computedTag) - } - // Test if Sum does not change state. - if len(data) > 1 { - mac.Reset() - mac.Write(data[0:1]) - mac.Sum(nil) - mac.Write(data[1:]) - computedTag = mac.Sum(nil) - if !bytes.Equal(tag, computedTag) { - t.Errorf("#%d: got %x, want %x", i, tag, computedTag) - } - } - } -} -func ExampleNewKMAC256() { - key := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long") - tag := make([]byte, 16) - msg := []byte("The quick brown fox jumps over the lazy dog") - // Example 1: Simple KMAC - k := kmac.NewKMAC256(key, len(tag), []byte("Partition1")) - k.Write(msg) - k.Sum(tag[:0]) - fmt.Println(hex.EncodeToString(tag)) - // Example 2: Different customization string produces different digest - k = kmac.NewKMAC256(key, 16, []byte("Partition2")) - k.Write(msg) - k.Sum(tag[:0]) - fmt.Println(hex.EncodeToString(tag)) - // Output: - //3814d78758add078334b8ab9e5c4f942 - //3762371e99e1e01ab17742b95c0360da -} \ No newline at end of file diff --git a/openpgp/mlkem_ecdh/mlkem_ecdh.go b/openpgp/mlkem_ecdh/mlkem_ecdh.go index a10f6d944..045561818 100644 --- a/openpgp/mlkem_ecdh/mlkem_ecdh.go +++ b/openpgp/mlkem_ecdh/mlkem_ecdh.go @@ -9,10 +9,8 @@ import ( "golang.org/x/crypto/sha3" "io" - "github.com/ProtonMail/go-crypto/internal/kmac" "github.com/ProtonMail/go-crypto/openpgp/aes/keywrap" "github.com/ProtonMail/go-crypto/openpgp/errors" - "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "github.com/ProtonMail/go-crypto/openpgp/internal/ecc" "github.com/cloudflare/circl/kem" ) @@ -84,7 +82,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, msg []byte) (kEphemeral, ecEphemera return nil, nil, nil, err } - kek, err := buildKey(pub, ecSS, ecEphemeral, pub.PublicPoint, kSS, kEphemeral) + kek, err := buildKey(pub, ecSS, ecEphemeral, pub.PublicPoint, kSS, kEphemeral, pub.PublicMlkem) if err != nil { return nil, nil, nil, err } @@ -111,7 +109,7 @@ func Decrypt(priv *PrivateKey, kEphemeral, ecEphemeral, ciphertext []byte) (msg return nil, err } - kek, err := buildKey(&priv.PublicKey, ecSS, ecEphemeral, priv.PublicPoint, kSS, kEphemeral) + kek, err := buildKey(&priv.PublicKey, ecSS, ecEphemeral, priv.PublicPoint, kSS, kEphemeral, priv.PublicMlkem) if err != nil { return nil, err } @@ -125,7 +123,7 @@ func Decrypt(priv *PrivateKey, kEphemeral, ecEphemeral, ciphertext []byte) (msg // buildKey implements the composite KDF as specified in // https://www.ietf.org/archive/id/draft-wussler-openpgp-pqc-03.html#name-key-combiner -func buildKey(pub *PublicKey, eccSecretPoint, eccEphemeral, eccPublicKey, kyberKeyShare, kyberEphemeral []byte) ([]byte, error) { +func buildKey(pub *PublicKey, eccSecretPoint, eccEphemeral, eccPublicKey, mlkemKeyShare, mlkemEphemeral []byte, mlkemPublicKey kem.PublicKey) ([]byte, error) { h := sha3.New256() // SHA3 never returns error @@ -134,20 +132,28 @@ func buildKey(pub *PublicKey, eccSecretPoint, eccEphemeral, eccPublicKey, kyberK _, _ = h.Write(eccPublicKey) eccKeyShare := h.Sum(nil) + serializedMlkemKey, err := mlkemPublicKey.MarshalBinary() + if err != nil { + return nil, err + } + // eccData = eccKeyShare || eccCipherText // mlkemData = mlkemKeyShare || mlkemCipherText // encData = counter || eccData || mlkemData || fixedInfo - k := kmac.NewKMAC256([]byte("OpenPGPCompositeKeyDerivationFunction"), algorithm.AES256.KeySize(), []byte("KDF")) + k := sha3.New256() - // KMAC never returns error + // SHA3 never returns error _, _ = k.Write([]byte{0x00, 0x00, 0x00, 0x01}) _, _ = k.Write(eccKeyShare) _, _ = k.Write(eccEphemeral) - _, _ = k.Write(kyberKeyShare) - _, _ = k.Write(kyberEphemeral) + _, _ = k.Write(eccPublicKey) + _, _ = k.Write(mlkemKeyShare) + _, _ = k.Write(mlkemEphemeral) + _, _ = k.Write(serializedMlkemKey) _, _ = k.Write([]byte{pub.AlgId}) + _, _ = k.Write([]byte("OpenPGPCompositeKDFv1")) - fmt.Printf("ecc:%x\nkyber:%x\n", eccKeyShare, kyberKeyShare) + fmt.Printf("ecc:%x\nkyber:%x\n", eccKeyShare, mlkemKeyShare) return k.Sum(nil), nil } diff --git a/openpgp/pqc_vectors_test.go b/openpgp/pqc_vectors_test.go index bd7e9c236..5c2420769 100644 --- a/openpgp/pqc_vectors_test.go +++ b/openpgp/pqc_vectors_test.go @@ -8,11 +8,10 @@ package openpgp import ( "bytes" - "crypto" "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/packet" + "strings" "testing" - "time" ) func dumpTestVector(t *testing.T, filename, vector string) { @@ -87,39 +86,47 @@ func encryptPqcMessageVector(t *testing.T, filename string, entity *Entity, conf } func TestV4EddsaPqKey(t *testing.T) { - eddsaConfig := &packet.Config{ - DefaultHash: crypto.SHA512, - Algorithm: packet.PubKeyAlgoEdDSA, - V6Keys: false, - DefaultCipher: packet.CipherAES256, - AEADConfig: &packet.AEADConfig { - DefaultMode: packet.AEADModeOCB, - }, - Time: func() time.Time { - parsed, _ := time.Parse("2006-01-02", "2013-07-01") - return parsed - }, - } - - entity, err := NewEntity("PQC user", "Test Key", "pqc-test-key@example.com", eddsaConfig) + //eddsaConfig := &packet.Config{ + // DefaultHash: crypto.SHA512, + // Algorithm: packet.PubKeyAlgoEdDSA, + // V6Keys: false, + // DefaultCipher: packet.CipherAES256, + // AEADConfig: &packet.AEADConfig { + // DefaultMode: packet.AEADModeOCB, + // }, + // Time: func() time.Time { + // parsed, _ := time.Parse("2006-01-02", "2013-07-01") + // return parsed + // }, + //} + // + //entity, err := NewEntity("PQC user", "Test Key", "pqc-test-key@example.com", eddsaConfig) + //if err != nil { + // t.Fatal(err) + //} + // + //kyberConfig := &packet.Config{ + // DefaultHash: crypto.SHA512, + // Algorithm: packet.PubKeyAlgoMlkem768X25519, + // V6Keys: false, + // Time: func() time.Time { + // parsed, _ := time.Parse("2006-01-02", "2013-07-01") + // return parsed + // }, + //} + // + //err = entity.AddEncryptionSubkey(kyberConfig) + //if err != nil { + // t.Fatal(err) + //} + + entities, err := ReadArmoredKeyRing(strings.NewReader(v4Ed25519Mlkem768X25519PrivateTestVector)) if err != nil { - t.Fatal(err) + t.Error(err) + return } - kyberConfig := &packet.Config{ - DefaultHash: crypto.SHA512, - Algorithm: packet.PubKeyAlgoMlkem768X25519, - V6Keys: false, - Time: func() time.Time { - parsed, _ := time.Parse("2006-01-02", "2013-07-01") - return parsed - }, - } - - err = entity.AddEncryptionSubkey(kyberConfig) - if err != nil { - t.Fatal(err) - } + entity := entities[0] serializePqSkVector(t, "v4-eddsa-sample-pk.asc", entity, true) serializePqPkVector(t, "v4-eddsa-sample-pk.asc", entity, true) @@ -148,40 +155,48 @@ func TestV4EddsaPqKey(t *testing.T) { func TestV6EddsaPqKey(t *testing.T) { - eddsaConfig := &packet.Config{ - DefaultHash: crypto.SHA512, - Algorithm: packet.PubKeyAlgoEd25519, - V6Keys: true, - DefaultCipher: packet.CipherAES256, - AEADConfig: &packet.AEADConfig { - DefaultMode: packet.AEADModeOCB, - }, - Time: func() time.Time { - parsed, _ := time.Parse("2006-01-02", "2013-07-01") - return parsed - }, - } - - entity, err := NewEntity("PQC user", "Test Key", "pqc-test-key@example.com", eddsaConfig) + //eddsaConfig := &packet.Config{ + // DefaultHash: crypto.SHA512, + // Algorithm: packet.PubKeyAlgoEd25519, + // V6Keys: true, + // DefaultCipher: packet.CipherAES256, + // AEADConfig: &packet.AEADConfig { + // DefaultMode: packet.AEADModeOCB, + // }, + // Time: func() time.Time { + // parsed, _ := time.Parse("2006-01-02", "2013-07-01") + // return parsed + // }, + //} + // + //entity, err := NewEntity("PQC user", "Test Key", "pqc-test-key@example.com", eddsaConfig) + //if err != nil { + // t.Fatal(err) + //} + + //kyberConfig := &packet.Config{ + // DefaultHash: crypto.SHA512, + // Algorithm: packet.PubKeyAlgoMlkem768X25519, + // V6Keys: true, + // Time: func() time.Time { + // parsed, _ := time.Parse("2006-01-02", "2013-07-01") + // return parsed + // }, + //} + // + //entity.Subkeys = []Subkey{} + //err = entity.AddEncryptionSubkey(kyberConfig) + //if err != nil { + // t.Fatal(err) + //} + + entities, err := ReadArmoredKeyRing(strings.NewReader(v6Ed25519Mlkem768X25519PrivateTestVector)) if err != nil { - t.Fatal(err) + t.Error(err) + return } - kyberConfig := &packet.Config{ - DefaultHash: crypto.SHA512, - Algorithm: packet.PubKeyAlgoMlkem768X25519, - V6Keys: true, - Time: func() time.Time { - parsed, _ := time.Parse("2006-01-02", "2013-07-01") - return parsed - }, - } - - entity.Subkeys = []Subkey{} - err = entity.AddEncryptionSubkey(kyberConfig) - if err != nil { - t.Fatal(err) - } + entity := entities[0] serializePqSkVector(t, "v6-eddsa-sample-pk.asc", entity, false) serializePqPkVector(t, "v6-eddsa-sample-pk.asc", entity, false) diff --git a/openpgp/read_write_test_data.go b/openpgp/read_write_test_data.go index a59b844e7..63e765949 100644 --- a/openpgp/read_write_test_data.go +++ b/openpgp/read_write_test_data.go @@ -603,64 +603,64 @@ Z2MPhqSLt9Vf5kAA/1RP8DeMB+q8U2n55xiSRnxP6+ddHg/Q7bZuUM0Cv+0M const v4Ed25519Mlkem768X25519PrivateV1MessageTestVector = `-----BEGIN PGP MESSAGE----- -wcPUA+RAz7r/1vNXafOEf/qo/UCjgP5MHXsUdzusv+Xtwa/q5/gtvWSKENMEm/ef -mwvHzlOW3jyHPr3wNkiRGNmZdEgHlRUxOF67AKfUqX1/H+RawlXrnu2O/7xDfn09 -1DOeYQYsG+VQe5eDfPOh6EAqvhglNG29enkwukjQuWJ0U2+SywRlh0J49oG0lZZi -tEonE6BX+dKo7JFAAW27I4+I15zamWCm7C2qXtcjlMq+68U6isstfJYBgCFoJLRV -9ME/JlwVQ/3OA4eagh1Ysw/s0Kbl8dWc/U+pUVINfLFnZbr8UnRx5QVjo47HzV9y -IPQcl1ETnrQqg4jH5cUB0wVB/OGSHEH1l1q7OwO4TBx9seRKza3wzHgXQyQn4jJn -WxG4Uf0rWwa/dbXpoGdxye7Di0HhFJBp4aPaPEm9RwmeD06HPGyurgQS2heW+ICR -X9q6HjxKmbIToWau7sEUZQh1isRD923zmZO1Cceiefwvv8RDErBaYRRfhoDHnwlf -haUkGDH55GC/mFgMUst7XjYLTpjTtM32bHHVoYyx3edk3V4C32dRP4geZRlq8MKb -3eNvTyZHPBXVeVjB2XVenMkju2qQvjAvr7xkJk5QvqRGZ3qy5JKPHjupPKMKR6Wv -90WtP9OPf6geE4K8g8dc4yqhqEf84IpWfwyUjglPwc8G7QURyc14INSgnVKQ8nzJ -26Y0YSuBG599cwnBXIv7TLOsrmpcR+3O/OiqztEXwBSFalWqC6SScWr51+K4RHpi -0Dg3GYOdeu9V12ofWhh5eoXiQxiThsDc0cYD2LwwITb/sXJW6jisvTSQSszuDJsg -w4LJGVIgk94GwBeYCa4w+YbFD/6bC+nd9hze5iWyAt4jx2XuYWHvI95wUvRal4Y6 -LcYKShZslef/9sZlrJ3O+oM8Tc+xjr7w860cw9bHBaRA3oZfDwVLRbJ63bh6dzLS -8Vj4UL0NiK9AlokOTlYTatKj2tkLaD6snZ5QaS916NniwvBiSozyCWKFPvKbIA5t -Fy7bWMk70wd7FJ5rOYsRvWOodcxxfYHLyOYCRikP5sOgelHJfIcqZZM/iMyKrUl5 -QXTe5SUMFKuAAWkv1nFgJqaBGkkYUN+aL6um4ogKJKxBArhUXtz5jp1zLQe6w7Pf -XtJ3rtnLMNIGbaJjN6jlSqB1lF88ljU6yL8lsfNfGuq6eLsNz1QD9sFoZyNKGVF8 -uGcX8KH07hyNCOPbn4jMZqnLfcEwT971KNeW0NNNLaVIjiYtYrEInYpnGP1fW0G7 -4ic4/CGZ0Jsti39rTPdz76n14EV5+HGGNtO92nXr7HhRvlvehZO+pPN2pPvAOQgp -378jEDnhdcFIUnWjaSN4HLjxN9X3tWosa9stVatcOB5n01+QAqdstgbARXiYhzZI -QOy5bk7GzM/xaD+4iMlsMgmhdvI3EuMrvzRHx95YvU+tc8UBhVtMpcxgp5tiPtw7 -wEFyPWYqTA6c+YGTZFzHNhqJ+DqLTlKP6+uYet4pCY6YLcu4z0JMG60Q4/MnuF2u -7pjPG7aRNGwr2/JFeaumSFbs5SrDPwDSOQGz9bQ6fbfGNm9Iw/Gq4EYrNx0raEVt -E1FD8+nRXcS1PribkWlu/qNd0yM+tXMXlryR6wAV3R4p9Q== -=h3Km +wcPUA+RAz7r/1vNXaUNGH8CAkSiFgunnUDqAiD9JSd3Sb7lMNUsWk6lzWiJicgky +S/vu0sSnRtxweWkoMr1y2ZaS45nXbEQyShiqHhZUKfVwtxbU+rGVH5oCgSvtTCrs +verZaFpqzqPWyZ8ApzJvjbGUDBuwns09dGIKvKoePT5DCrqXlsW4EA8gFJbiXeb3 +E7nsyg3l2uMzbt6FHtYoa6qq9Q0PsUiGte52nXXWEnmBOGUfmCkVsgmHDmz63BLT +1xXuZ5YopZkhhpjTNtvWtXc6MIaqnh6XtAcg8ZoaH0iferpbHEp9+M4bv5YDjzji +vv83rBQN4cBaS1/TSmBkNJHmxcyT1AOOXY2ZbmxQBORhGOTrFz3w8R78MYkEvB6x +JAjoYirpsyNLJzdewpXEYrPQq4Ey8EG2+qDY47vQkQaYcSFFoxYQ8MpHXmmgJ2bp +D13g/lQlSHcdWX2L59Wa1dhKRVnUyeEtO5c06FKJ7QOrywNjPdVciPVCx6bBfVd2 +6qiWLynSGnzGaKd1YyaviioCm48Ydu5q8Z+QbEANbKW1azVAWCuxuiomE3RBvf1O +8d30UvBnImEf+9ANDxzmjIG2lW39U591Jbv0pL00at3tIMQN2wwiduP1KZ1dilWa +gEkdPjl6Q68ov0vRCYMAZizj4pMZbsUdge2Jj9GieObnp+w25pJu9nBeI6iqYmwd +Ny1U3OuvzbEUsNfKcHoQd9Cem8EZn+5ICk7eqsTkZq69oYfIVRyzEEc/X9562nzh +6B+X4CHZY/C8UCWougQriG4KVszM4myOgekKg0kNVIWgE2y7Z//S9c2twdxRWT/a +8QC4p7QX7JRgzDD9erkj/9J3hKwHxDHShKB5jsVaGO+BxtFSCiiTmgeo7+SAnJwU +Mi/N0UiI2BbKdo4KmdDPUVDyobBjCjeXil7Kg7pTU0vewPZQDLl9X16CcXCB60HL +fkDGpcYbjkZYbmB449sQfaLvxRMHomP4TY4PEfANIXdWmk1mS0/+zNzMQ9+Xderc +8P/EdKDKF5yr7IzSNoxuLiIWpyWJj+5QmAwup9mVv5gkh5RPnUQ0fgQ1vU8K9PMz +OmYqlX2W4gPn29UovjkbGH+lEzazEzA7VZWHXG86NVN8WMXqdQvMJcmMRZhDmC3F +kCII5zc6dxFXjNUgaAqV8eBqvRBbgCqK+6HSwCMY7jNFhFIy+Nj/9BYU/ereax0t +Zlsk7XDK9lMZUidh5+VeEqbyMsLQ0YiyO7VJ5VdiPESXHjPkzxo42XZJELuBVC9D +ArAX2Qip+oV1RXzhu/SeJdRQufGSENeZpGiG4tW24dpROh40I5TgXmpd4ALhuh1S +PrepCNhXuFtKDIStKZEmCknPAGWAkLYZz5rAaMtztdGvzlektn+8CDtSo3d6FUww +dp68ZtSMMb5HGscAoiDoOTiB5KVPSd80s3EPXlsgQSfHuSUHTvmD8G6q4hqGXMeV +IUdwjwTvDMfW7CU5zqiV01SO6dXKsFyjLJrT57kpCbQ/2fhoMC+kNcXpzI+Z65yI +jCP6Sjv+cVh7tv55kTKAPHO5VE3MDxvSOQHpUQ0zora+lfzpLUahfv8uZ4Q4J3L6 +mkHfXuplyv3LcunejQDog2bhakqbrb5lg3fZGYNagykZxw== +=2Xhi -----END PGP MESSAGE-----` const v4Ed25519Mlkem768X25519PrivateV2MessageTestVector = `-----BEGIN PGP MESSAGE----- -wcPhBhUEvWfZg4iBPoi/NJDz5EDPuv/W81dp/h3ny6MDFKIjw8Jva/pK0mlJJMbX -RtJ2+idWKUL4/Evq2JBL2pky3VeCkhJIAnKdMXBvuucpNC4xVhCREpPquOsQcJE1 -IyR5kdk0uOw/7T5i7i9zb3N8Mn4jObYNxem0PbD44xYfF4BcNZqWPhLSwdFp+uti -FDVcsAtaruQQnwcb0tE9KUxMHsH2QxuG6Xnm+a1v3fds/rp/DqrR1vTcwbeUBej9 -AcrWhRI+KrE80WtMqqB0nvj74Jsx7xrYKyDqi7C50PG1LwTfFmO1kuIOGwEVh3AL -f9vesNee8+QWqJHMuSaqTsndts7Pq2EQ1fzdsrhYvseFEuiITj6OHnvmERjhkVRt -M36v3cA8GmcKI2YLa+fNvyagjgkoUycjNopK94/KQk8DY4JnKEbMHJ1BvUQ6mXkZ -ZeQXEt9gBHMZvTPE4ZPKSR14tki9YbjCvGcklEx1BEhONMo+03C07H/AHMtk5Ia1 -BFDF3dRkOhyXLfJCNKhJL4Sq7Z07CqKYCCzEq6WgKQUlWmiJzEtZKmh61LX3FaVU -A8+iK56QBvYyFUv/T9mGIBvF6qM+1l9BUSDim81EEN3FVKuo5QJ+tEbuKOrDWMTQ -klx3iEmGFeW8/N0gxTMpDKQRqDbkhdwFoM1c1L61NeCfDvTiWWVQQg00Z/n38gGC -S4MC8szKWPPlmtPYsXbyITMLpErgbIfr3IPfwRkm1RWVPQ/T7dm0Iz8ufeVTAqv+ -4+WgeILpQbFf/PmKHlZJnyj+munVaLaV9ed8g/0ncfZ0Vn9sMzGXifAjJ7vT8t/2 -ojSqc1AQuhoNguI3xFUCaUEzmWzOl3ONZhgDr4WTJdvfW/8IHn2y0Kkn5buqLAO5 -LOvrksFgkuy3N21OzgI+H5SeCqOGt5NKgyMAUGKEa5a6ApG/DSecXJ38yr4hTG6k -IGxfd9dlezcdByrohFsRHC93XUSlTnxTqdYmuhK8x4me6QblJFEJhoDTr3lrKTQE -gXC5ncdTLKLLINnZgFRc0oFABKGATf/708nt/vkuhyNroCY2NxGKoem3M8P5radp -vKJ7qRi+ePBmxwPhb5mWVf7G5y509GgVhKUFUWCzvyoyp1HLtekARKrxBAElXo4D -RINA468O/Sx9rWDFFkaShsXqQEhe06C3IhoG6vqagdB82LYcisCWEAKd/hZE99Ub -EWawnQor/jrHhGNQId1nZEwpEE2/cndU3Np0mhoGF/kkjyGah8wxjFRZhX2b+w3M -jmyFyOFGog6SDK1dK6+Vdki3fJFvBCx/uLmuLiNQo2MYeG3B4W30jNDlkxZ2DA14 -1zPXL8S3t54ZCtqiqDO63SNW18o2SB9AJpmSYYF34LO29VJnWIK5/94tIsfwHbAg -P/JdfRmSXkUYDTwJcYR1SOp8IIWwhmybnYctHS/n1q+WnzMj0jJIe4SI9ifoJg6n -+ntRfsqR1B3fcTAKN0XK6pnNy+pJ1BCVDOYDz5RGsAa61wJdVK/mXEg7VyjMlf0t -EnPzSfwfotMPoZs9n+MuK/BO0AX8DqzY8SluBALG6Eu5OV+A0lQCCQIMeNuKCuzH -CoYERR8ds1jE9m+xLEGK7i1+zr5FSdzGowHh4xMo95Zk5JUubl5rYvcYbHgVVKKE -9mwM7/4Q5mXZ2xvsBftkujgamZM2UN9UYSA= +wcPhBhUEvWfZg4iBPoi/NJDz5EDPuv/W81dpZ1Yz1yu1Dk/HK2JuEmE6RavqzhvT +i508AZhPxC08BxfNFar+uyZCNyMrUSrY0qY8H61GTtx1+O9VynXl8uXtS1nTDGJ9 +vCR+EvH6rT/gOPQB8HUhX6Ps97Yqi/Iys1gfS8n961pScwIYpPJzUWfUUKjIT55W +htkh9aIB6unqzwUDi3p4oRZRm67j1ZP14SLyonAG2tXtCZyu1An62UHeOyNl1/6Z +CgC3egTf6lz26US15T8AP54AO77LOf9KwLpUYcwvSExqHGgmhS0Mil6WnFyuJUDB +7A2T2p/koW7TDaqoxhWsxY2isiH1SmAxNxzMnrGd7rNpPJ/k/r42bILfOuG0TRUN +zqC9ph6OdydSyhHkN5G4eOYQqqvk19/lfLuHWlNwfNcn/2PsgsxLxNj7ltVn90W0 +qLubPWrujn/DhLl+hs2xXDOudpcztUqxcBnrsSaHlaebjQoDfttVAQj2jjdNXRjZ +uNRnRfcG9s3sO3b8d4ed6tk6U+nMrE2dZCBjTagqvD07Z1TpZDh7t86V3X16o/ps +jxW42s+YR589b88IZcieZRbKVtXt00pn2tn95kpvL3d8nAkaiPUhrowQUz0jpn8c +CDBNAn1j690qM3pD5XJlwverC2cmJH1Hjobnrhi6X1k2lQxweX28p+R9NQjSoX0h +ORuE0/Wpi15y0xmr2EzjcZ/6vPncy/IrYJCYmx9+aWQAjrKjizzNFTt73kf1xba5 +t4tbZkj9xgdDJXq3bAqB0/JeeTb4aTCk+n4olVYzCnMtLgj+1fWPClMModACmFOG +1+bw5Q91/7euo363sw5UwgU1JhSQ/xcKNyJQsnklWkLMJNB1Yhj/C32lEmLntigv +UOO510+ehA7D5ftef8cMfEIm73HrBBiLfixvVTR8AQV4hiV/mzKP7weM7kxvAvbz +ir4jt3uSBOuhTjzq2is/S3D2K+O8FZqGIbkDhnKd98LbEA2cn9nTfsbV+TVXCmaS +lHNojVxPL2pUKxedV5skvfflRFciuP7UNsf8myHe7wdfPdSzMsbytDEwID3vcsme +fBqZdEZxqv/mNnn38TfHMSCF+yv5XbF9ham4DIcqNlkYud1ipEFFbcBZ0o9nUIWp +diSY7KGAtVF224dtcr3FTHGuBnayDq+Yk++VhF4Bb3uPVuwrkf7Bncp1aYEQfkhI +HwF3X6GnwC3y7kpbkU1rOq7yXv/0mRyGpVQlW/Yf3qT1buxcWt5BvXBmKzbBpVg/ +0B9vpzrlFsT0Pb2GHuQ6U+9JoZ+ePnRMVdDz93RCGr1kQlyY15K1b+yILJiV6oOL +OxoxXHnr5soIumxCqv+6oAm4SdQVJLELQK72x1dVKJ90jUOgYCeOY61NsC9BFWHT +h0itUEnwWMjKg73z00bthndwfEXHBJLrHizkcv+pwD8M5wb/9H6HU4x8ELSr5Fyn +WjSoa2739wmJkoJY5ifaic3L8UXJeLuEZnVG9tUrl9ohHO8RNR3Vc/uHmyhImoYp +RL4rcc6YpuyextmYu9S9LkPR5Bzr+mFeJDeXbA7GJm9eofdw0lQCCQIMAGc2j84/ +tfivyP5YrgQ8uBt9iwJN3IYRBy8qdr9JUyxkpkOEshV6XE4g3Orpbx0ZdrxbKmDS +7eJl5fSust3gb2KfaAoWkFQivVJP2KTl5gw= -----END PGP MESSAGE-----` const v6Ed25519Mlkem768X25519PrivateTestVector = `-----BEGIN PGP PRIVATE KEY BLOCK----- @@ -801,31 +801,31 @@ g+Bld9lBSVmEdMJnOX2ZHOdEoRV4bm1U4aPuhrKL/d8lkIgM const v6Ed25519Mlkem768X25519PrivateMessageTestVector = `-----BEGIN PGP MESSAGE----- -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 -----END PGP MESSAGE-----`