| // Copyright 2018 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // Package testutil provides common methods needed in test code. |
| package testutil |
| |
| import ( |
| "bytes" |
| "crypto/ecdsa" |
| "crypto/ed25519" |
| "crypto/rand" |
| "encoding/gob" |
| "errors" |
| "fmt" |
| "log" |
| "math" |
| "strconv" |
| "strings" |
| |
| "google.golang.org/protobuf/proto" |
| "github.com/google/tink/go/core/registry" |
| subtledaead "github.com/google/tink/go/daead/subtle" |
| subtlehybrid "github.com/google/tink/go/hybrid/subtle" |
| "github.com/google/tink/go/keyset" |
| "github.com/google/tink/go/mac" |
| "github.com/google/tink/go/subtle/random" |
| "github.com/google/tink/go/subtle" |
| "github.com/google/tink/go/tink" |
| |
| cmacpb "github.com/google/tink/go/proto/aes_cmac_go_proto" |
| aescmacprfpb "github.com/google/tink/go/proto/aes_cmac_prf_go_proto" |
| ctrhmacpb "github.com/google/tink/go/proto/aes_ctr_hmac_streaming_go_proto" |
| gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto" |
| gcmhkdfpb "github.com/google/tink/go/proto/aes_gcm_hkdf_streaming_go_proto" |
| gcmsivpb "github.com/google/tink/go/proto/aes_gcm_siv_go_proto" |
| aspb "github.com/google/tink/go/proto/aes_siv_go_proto" |
| commonpb "github.com/google/tink/go/proto/common_go_proto" |
| ecdsapb "github.com/google/tink/go/proto/ecdsa_go_proto" |
| eciespb "github.com/google/tink/go/proto/ecies_aead_hkdf_go_proto" |
| ed25519pb "github.com/google/tink/go/proto/ed25519_go_proto" |
| hkdfprfpb "github.com/google/tink/go/proto/hkdf_prf_go_proto" |
| hmacpb "github.com/google/tink/go/proto/hmac_go_proto" |
| hmacprfpb "github.com/google/tink/go/proto/hmac_prf_go_proto" |
| tinkpb "github.com/google/tink/go/proto/tink_go_proto" |
| ) |
| |
| // DummyAEADKeyManager is a dummy implementation of the KeyManager interface. |
| // It returns DummyAEAD when GetPrimitive() functions are called. |
| type DummyAEADKeyManager struct{} |
| |
| var _ registry.KeyManager = (*DummyAEADKeyManager)(nil) |
| |
| // Primitive constructs a primitive instance for the key given in |
| // serializedKey, which must be a serialized key protocol buffer handled by this manager. |
| func (km *DummyAEADKeyManager) Primitive(serializedKey []byte) (interface{}, error) { |
| return new(DummyAEAD), nil |
| } |
| |
| // NewKey generates a new key according to specification in serializedKeyFormat. |
| func (km *DummyAEADKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { |
| return nil, fmt.Errorf("not implemented") |
| } |
| |
| // NewKeyData generates a new KeyData according to specification in serializedkeyFormat. |
| func (km *DummyAEADKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { |
| return nil, fmt.Errorf("not implemented") |
| } |
| |
| // DoesSupport returns true iff this KeyManager supports key type identified by typeURL. |
| func (km *DummyAEADKeyManager) DoesSupport(typeURL string) bool { |
| return typeURL == AESGCMTypeURL |
| } |
| |
| // TypeURL returns the type URL. |
| func (km *DummyAEADKeyManager) TypeURL() string { |
| return AESGCMTypeURL |
| } |
| |
| // DummyAEAD is a dummy implementation of AEAD interface. It "encrypts" data |
| // with a simple serialization capturing the dummy name, plaintext, and |
| // associated data, and "decrypts" it by reversing this and checking that the |
| // name and associated data match. |
| type DummyAEAD struct { |
| Name string |
| } |
| |
| type dummyAEADData struct { |
| Name string |
| Plaintext []byte |
| AssociatedData []byte |
| } |
| |
| // Encrypt encrypts the plaintext. |
| func (a *DummyAEAD) Encrypt(plaintext []byte, associatedData []byte) ([]byte, error) { |
| buf := new(bytes.Buffer) |
| encoder := gob.NewEncoder(buf) |
| err := encoder.Encode(dummyAEADData{ |
| Name: a.Name, |
| Plaintext: plaintext, |
| AssociatedData: associatedData, |
| }) |
| if err != nil { |
| return nil, fmt.Errorf("dummy aead encrypt: %v", err) |
| } |
| return buf.Bytes(), nil |
| } |
| |
| // Decrypt decrypts the ciphertext. |
| func (a *DummyAEAD) Decrypt(ciphertext []byte, associatedData []byte) ([]byte, error) { |
| data := dummyAEADData{} |
| decoder := gob.NewDecoder(bytes.NewBuffer(ciphertext)) |
| if err := decoder.Decode(&data); err != nil { |
| return nil, fmt.Errorf("dummy aead decrypt: invalid data: %v", err) |
| } |
| if data.Name != a.Name || !bytes.Equal(data.AssociatedData, associatedData) { |
| return nil, errors.New("dummy aead encrypt: name/associated data mismatch") |
| } |
| return data.Plaintext, nil |
| } |
| |
| // AlwaysFailingAead fails encryption and decryption operations. |
| type AlwaysFailingAead struct { |
| Error error |
| } |
| |
| var _ (tink.AEAD) = (*AlwaysFailingAead)(nil) |
| |
| // NewAlwaysFailingAead creates a new always failing AEAD. |
| func NewAlwaysFailingAead(err error) tink.AEAD { |
| return &AlwaysFailingAead{Error: err} |
| } |
| |
| // Encrypt returns an error on encryption. |
| func (a *AlwaysFailingAead) Encrypt(plaintext []byte, associatedData []byte) ([]byte, error) { |
| return nil, fmt.Errorf("AlwaysFailingAead will always fail on encryption: %v", a.Error) |
| } |
| |
| // Decrypt returns an error on decryption. |
| func (a *AlwaysFailingAead) Decrypt(ciphertext []byte, associatedData []byte) ([]byte, error) { |
| return nil, fmt.Errorf("AlwaysFailingAead will always fail on decryption: %v", a.Error) |
| } |
| |
| // AlwaysFailingDeterministicAead fails encryption and decryption operations. |
| type AlwaysFailingDeterministicAead struct { |
| Error error |
| } |
| |
| var _ (tink.DeterministicAEAD) = (*AlwaysFailingDeterministicAead)(nil) |
| |
| // NewAlwaysFailingDeterministicAead creates a new always failing AEAD. |
| func NewAlwaysFailingDeterministicAead(err error) tink.DeterministicAEAD { |
| return &AlwaysFailingDeterministicAead{Error: err} |
| } |
| |
| // EncryptDeterministically returns an error on encryption. |
| func (a *AlwaysFailingDeterministicAead) EncryptDeterministically(plaintext []byte, associatedData []byte) ([]byte, error) { |
| return nil, fmt.Errorf("AlwaysFailingDeterministicAead will always fail on encryption: %v", a.Error) |
| } |
| |
| // DecryptDeterministically returns an error on decryption. |
| func (a *AlwaysFailingDeterministicAead) DecryptDeterministically(ciphertext []byte, associatedData []byte) ([]byte, error) { |
| return nil, fmt.Errorf("AlwaysFailingDeterministicAead will always fail on decryption: %v", a.Error) |
| } |
| |
| // TestKeyManager is key manager which can be setup to return an arbitrary primitive for a type URL |
| // useful for testing. |
| type TestKeyManager struct { |
| primitive interface{} |
| typeURL string |
| } |
| |
| var _ registry.KeyManager = (*TestKeyManager)(nil) |
| |
| // NewTestKeyManager creates a new key manager that returns a specific primitive for a typeURL. |
| func NewTestKeyManager(primitive interface{}, typeURL string) registry.KeyManager { |
| return &TestKeyManager{ |
| primitive: primitive, |
| typeURL: typeURL, |
| } |
| } |
| |
| // Primitive constructs a primitive instance for the key given input key. |
| func (km *TestKeyManager) Primitive(serializedKey []byte) (interface{}, error) { |
| return km.primitive, nil |
| } |
| |
| // NewKey generates a new key according to specification in serializedKeyFormat. |
| func (km *TestKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { |
| return nil, fmt.Errorf("TestKeyManager: not implemented") |
| } |
| |
| // NewKeyData generates a new KeyData according to specification in serializedkeyFormat. |
| func (km *TestKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { |
| return nil, fmt.Errorf("TestKeyManager: not implemented") |
| } |
| |
| // DoesSupport returns true if this KeyManager supports key type identified by typeURL. |
| func (km *TestKeyManager) DoesSupport(typeURL string) bool { |
| return typeURL == km.typeURL |
| } |
| |
| // TypeURL returns the type URL. |
| func (km *TestKeyManager) TypeURL() string { |
| return km.typeURL |
| } |
| |
| // DummySigner is a dummy implementation of the Signer interface. |
| type DummySigner struct { |
| aead DummyAEAD |
| } |
| |
| // NewDummySigner creates a new dummy signer with the specified name. The name |
| // is used to pair with the DummyVerifier. |
| func NewDummySigner(name string) *DummySigner { |
| return &DummySigner{DummyAEAD{Name: "dummy public key:" + name}} |
| } |
| |
| // Sign signs data. |
| func (s *DummySigner) Sign(data []byte) ([]byte, error) { |
| return s.aead.Encrypt(nil, data) |
| } |
| |
| // DummyVerifier is a dummy implementation of the Signer interface. |
| type DummyVerifier struct { |
| aead DummyAEAD |
| } |
| |
| // Verify verifies data. |
| func (v *DummyVerifier) Verify(sig, data []byte) error { |
| _, err := v.aead.Decrypt(sig, data) |
| return err |
| } |
| |
| // NewDummyVerifier creates a new dummy verifier with the specified name. The |
| // name is used to pair with the DummySigner. |
| func NewDummyVerifier(name string) *DummyVerifier { |
| return &DummyVerifier{DummyAEAD{Name: "dummy public key:" + name}} |
| } |
| |
| // DummyMAC is a dummy implementation of Mac interface. |
| type DummyMAC struct { |
| Name string |
| } |
| |
| // ComputeMAC computes a message authentication code (MAC) for data. |
| func (h *DummyMAC) ComputeMAC(data []byte) ([]byte, error) { |
| var m []byte |
| m = append(m, data...) |
| m = append(m, h.Name...) |
| return m, nil |
| } |
| |
| // VerifyMAC verifies whether mac is a correct message authentication code |
| // (MAC) for data. |
| func (h *DummyMAC) VerifyMAC(mac []byte, data []byte) error { |
| return nil |
| } |
| |
| // DummyKMSClient is a dummy implementation of a KMS Client. |
| type DummyKMSClient struct{} |
| |
| var _ registry.KMSClient = (*DummyKMSClient)(nil) |
| |
| // Supported true if this client does support keyURI |
| func (d *DummyKMSClient) Supported(keyURI string) bool { |
| return keyURI == "dummy" |
| } |
| |
| // GetAEAD gets an Aead backend by keyURI. |
| func (d *DummyKMSClient) GetAEAD(keyURI string) (tink.AEAD, error) { |
| return &DummyAEAD{}, nil |
| } |
| |
| // NewTestAESGCMKeyset creates a new Keyset containing an AESGCMKey. |
| func NewTestAESGCMKeyset(primaryOutputPrefixType tinkpb.OutputPrefixType) *tinkpb.Keyset { |
| keyData := NewAESGCMKeyData(16) |
| return NewTestKeyset(keyData, primaryOutputPrefixType) |
| } |
| |
| // NewTestAESGCMSIVKeyset creates a new Keyset containing an AESGCMSIVKey. |
| func NewTestAESGCMSIVKeyset(primaryOutputPrefixType tinkpb.OutputPrefixType) *tinkpb.Keyset { |
| keyData := NewAESGCMSIVKeyData(16) |
| return NewTestKeyset(keyData, primaryOutputPrefixType) |
| } |
| |
| // NewTestAESSIVKeyset creates a new Keyset containing an AesSivKey. |
| func NewTestAESSIVKeyset(primaryOutputPrefixType tinkpb.OutputPrefixType) *tinkpb.Keyset { |
| keyValue := random.GetRandomBytes(subtledaead.AESSIVKeySize) |
| key := &aspb.AesSivKey{ |
| Version: AESSIVKeyVersion, |
| KeyValue: keyValue, |
| } |
| serializedKey, err := proto.Marshal(key) |
| if err != nil { |
| log.Fatalf("failed serializing proto: %v", err) |
| } |
| keyData := NewKeyData(AESSIVTypeURL, serializedKey, tinkpb.KeyData_SYMMETRIC) |
| return NewTestKeyset(keyData, primaryOutputPrefixType) |
| } |
| |
| // NewTestHMACKeyset creates a new Keyset containing a HMACKey. |
| func NewTestHMACKeyset(tagSize uint32, primaryOutputPrefixType tinkpb.OutputPrefixType) *tinkpb.Keyset { |
| keyData := NewHMACKeyData(commonpb.HashType_SHA256, tagSize) |
| return NewTestKeyset(keyData, primaryOutputPrefixType) |
| } |
| |
| // NewTestAESGCMHKDFKeyset creates a new Keyset containing an AESGCMHKDFKey. |
| func NewTestAESGCMHKDFKeyset() *tinkpb.Keyset { |
| const ( |
| keySize = 16 |
| derivedKeySize = 16 |
| ciphertextSegmentSize = 4096 |
| ) |
| keyData := NewAESGCMHKDFKeyData(keySize, derivedKeySize, commonpb.HashType_SHA256, ciphertextSegmentSize) |
| return NewTestKeyset(keyData, tinkpb.OutputPrefixType_RAW) |
| } |
| |
| // NewTestKeyset creates a new test Keyset. |
| func NewTestKeyset(keyData *tinkpb.KeyData, primaryOutputPrefixType tinkpb.OutputPrefixType) *tinkpb.Keyset { |
| primaryKey := NewKey(keyData, tinkpb.KeyStatusType_ENABLED, 42, primaryOutputPrefixType) |
| rawKey := NewKey(keyData, tinkpb.KeyStatusType_ENABLED, 43, tinkpb.OutputPrefixType_RAW) |
| legacyKey := NewKey(keyData, tinkpb.KeyStatusType_ENABLED, 44, tinkpb.OutputPrefixType_LEGACY) |
| tinkKey := NewKey(keyData, tinkpb.KeyStatusType_ENABLED, 45, tinkpb.OutputPrefixType_TINK) |
| crunchyKey := NewKey(keyData, tinkpb.KeyStatusType_ENABLED, 46, tinkpb.OutputPrefixType_CRUNCHY) |
| keys := []*tinkpb.Keyset_Key{primaryKey, rawKey, legacyKey, tinkKey, crunchyKey} |
| return NewKeyset(primaryKey.KeyId, keys) |
| } |
| |
| // NewDummyKey returns a dummy key that doesn't contain actual key material. |
| func NewDummyKey(keyID int, status tinkpb.KeyStatusType, outputPrefixType tinkpb.OutputPrefixType) *tinkpb.Keyset_Key { |
| return &tinkpb.Keyset_Key{ |
| KeyData: new(tinkpb.KeyData), |
| Status: status, |
| KeyId: uint32(keyID), |
| OutputPrefixType: outputPrefixType, |
| } |
| } |
| |
| // NewECDSAParams creates a ECDSAParams with the specified parameters. |
| func NewECDSAParams(hashType commonpb.HashType, curve commonpb.EllipticCurveType, encoding ecdsapb.EcdsaSignatureEncoding) *ecdsapb.EcdsaParams { |
| return &ecdsapb.EcdsaParams{ |
| HashType: hashType, |
| Curve: curve, |
| Encoding: encoding, |
| } |
| } |
| |
| // NewECDSAKeyFormat creates a ECDSAKeyFormat with the specified parameters. |
| func NewECDSAKeyFormat(params *ecdsapb.EcdsaParams) *ecdsapb.EcdsaKeyFormat { |
| return &ecdsapb.EcdsaKeyFormat{Params: params} |
| } |
| |
| // NewECDSAPrivateKey creates a ECDSAPrivateKey with the specified paramaters. |
| func NewECDSAPrivateKey(version uint32, publicKey *ecdsapb.EcdsaPublicKey, keyValue []byte) *ecdsapb.EcdsaPrivateKey { |
| return &ecdsapb.EcdsaPrivateKey{ |
| Version: version, |
| PublicKey: publicKey, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewECDSAPublicKey creates a ECDSAPublicKey with the specified paramaters. |
| func NewECDSAPublicKey(version uint32, params *ecdsapb.EcdsaParams, x, y []byte) *ecdsapb.EcdsaPublicKey { |
| return &ecdsapb.EcdsaPublicKey{ |
| Version: version, |
| Params: params, |
| X: x, |
| Y: y, |
| } |
| } |
| |
| // NewRandomECDSAPrivateKey creates an ECDSAPrivateKey with randomly generated key material. |
| func NewRandomECDSAPrivateKey(hashType commonpb.HashType, curve commonpb.EllipticCurveType) *ecdsapb.EcdsaPrivateKey { |
| curveName := commonpb.EllipticCurveType_name[int32(curve)] |
| priv, _ := ecdsa.GenerateKey(subtle.GetCurve(curveName), rand.Reader) |
| params := NewECDSAParams(hashType, curve, ecdsapb.EcdsaSignatureEncoding_DER) |
| publicKey := NewECDSAPublicKey(ECDSAVerifierKeyVersion, params, priv.X.Bytes(), priv.Y.Bytes()) |
| return NewECDSAPrivateKey(ECDSASignerKeyVersion, publicKey, priv.D.Bytes()) |
| } |
| |
| // NewRandomECDSAPublicKey creates an ECDSAPublicKey with randomly generated key material. |
| func NewRandomECDSAPublicKey(hashType commonpb.HashType, curve commonpb.EllipticCurveType) *ecdsapb.EcdsaPublicKey { |
| return NewRandomECDSAPrivateKey(hashType, curve).PublicKey |
| } |
| |
| // GetECDSAParamNames returns the string representations of each parameter in |
| // the given ECDSAParams. |
| func GetECDSAParamNames(params *ecdsapb.EcdsaParams) (string, string, string) { |
| hashName := commonpb.HashType_name[int32(params.HashType)] |
| curveName := commonpb.EllipticCurveType_name[int32(params.Curve)] |
| encodingName := ecdsapb.EcdsaSignatureEncoding_name[int32(params.Encoding)] |
| return hashName, curveName, encodingName |
| } |
| |
| // NewED25519PrivateKey creates an ED25519PrivateKey with randomly generated key material. |
| func NewED25519PrivateKey() *ed25519pb.Ed25519PrivateKey { |
| public, private, _ := ed25519.GenerateKey(rand.Reader) |
| publicProto := &ed25519pb.Ed25519PublicKey{ |
| Version: ED25519SignerKeyVersion, |
| KeyValue: public, |
| } |
| return &ed25519pb.Ed25519PrivateKey{ |
| Version: ED25519SignerKeyVersion, |
| PublicKey: publicProto, |
| KeyValue: private.Seed(), |
| } |
| } |
| |
| // NewED25519PublicKey creates an ED25519PublicKey with randomly generated key material. |
| func NewED25519PublicKey() *ed25519pb.Ed25519PublicKey { |
| return NewED25519PrivateKey().PublicKey |
| } |
| |
| // NewAESGCMKey creates a randomly generated AESGCMKey. |
| func NewAESGCMKey(keyVersion uint32, keySize uint32) *gcmpb.AesGcmKey { |
| keyValue := random.GetRandomBytes(keySize) |
| return &gcmpb.AesGcmKey{ |
| Version: keyVersion, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewAESGCMKeyData creates a KeyData containing a randomly generated AESGCMKey. |
| func NewAESGCMKeyData(keySize uint32) *tinkpb.KeyData { |
| serializedKey, err := proto.Marshal(NewAESGCMKey(AESGCMKeyVersion, keySize)) |
| if err != nil { |
| log.Fatalf("failed serializing proto: %v", err) |
| } |
| return NewKeyData(AESGCMTypeURL, serializedKey, tinkpb.KeyData_SYMMETRIC) |
| } |
| |
| // NewAESGCMKeyFormat returns a new AESGCMKeyFormat. |
| func NewAESGCMKeyFormat(keySize uint32) *gcmpb.AesGcmKeyFormat { |
| return &gcmpb.AesGcmKeyFormat{ |
| KeySize: keySize, |
| } |
| } |
| |
| // NewAESGCMSIVKey creates a randomly generated AESGCMSIVKey. |
| func NewAESGCMSIVKey(keyVersion, keySize uint32) *gcmsivpb.AesGcmSivKey { |
| keyValue := random.GetRandomBytes(keySize) |
| return &gcmsivpb.AesGcmSivKey{ |
| Version: keyVersion, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewAESGCMSIVKeyData creates a KeyData containing a randomly generated AESGCMSIVKey. |
| func NewAESGCMSIVKeyData(keySize uint32) *tinkpb.KeyData { |
| serializedKey, err := proto.Marshal(NewAESGCMSIVKey(AESGCMKeyVersion, keySize)) |
| if err != nil { |
| log.Fatalf("NewAESGCMSIVKeyData(keySize=%d): Failed serializing proto; err=%v", keySize, err) |
| } |
| return NewKeyData(AESGCMTypeURL, serializedKey, tinkpb.KeyData_SYMMETRIC) |
| } |
| |
| // NewAESGCMSIVKeyFormat returns a new AESGCMKeyFormat. |
| func NewAESGCMSIVKeyFormat(keySize uint32) *gcmsivpb.AesGcmSivKeyFormat { |
| return &gcmsivpb.AesGcmSivKeyFormat{ |
| KeySize: keySize, |
| } |
| } |
| |
| // NewAESGCMHKDFKey creates a randomly generated AESGCMHKDFKey. |
| func NewAESGCMHKDFKey(keyVersion, keySize, derivedKeySize uint32, hkdfHashType commonpb.HashType, ciphertextSegmentSize uint32) *gcmhkdfpb.AesGcmHkdfStreamingKey { |
| keyValue := random.GetRandomBytes(keySize) |
| return &gcmhkdfpb.AesGcmHkdfStreamingKey{ |
| Version: keyVersion, |
| KeyValue: keyValue, |
| Params: &gcmhkdfpb.AesGcmHkdfStreamingParams{ |
| CiphertextSegmentSize: ciphertextSegmentSize, |
| DerivedKeySize: derivedKeySize, |
| HkdfHashType: hkdfHashType, |
| }, |
| } |
| } |
| |
| // NewAESGCMHKDFKeyData creates a KeyData containing a randomly generated AESGCMHKDFKey. |
| func NewAESGCMHKDFKeyData(keySize, derivedKeySize uint32, hkdfHashType commonpb.HashType, ciphertextSegmentSize uint32) *tinkpb.KeyData { |
| serializedKey, err := proto.Marshal(NewAESGCMHKDFKey(AESGCMHKDFKeyVersion, keySize, derivedKeySize, hkdfHashType, ciphertextSegmentSize)) |
| if err != nil { |
| log.Fatalf("failed serializing proto: %v", err) |
| } |
| return NewKeyData(AESGCMHKDFTypeURL, serializedKey, tinkpb.KeyData_SYMMETRIC) |
| } |
| |
| // NewAESGCMHKDFKeyFormat returns a new AESGCMHKDFKeyFormat. |
| func NewAESGCMHKDFKeyFormat(keySize, derivedKeySize uint32, hkdfHashType commonpb.HashType, ciphertextSegmentSize uint32) *gcmhkdfpb.AesGcmHkdfStreamingKeyFormat { |
| return &gcmhkdfpb.AesGcmHkdfStreamingKeyFormat{ |
| KeySize: keySize, |
| Params: &gcmhkdfpb.AesGcmHkdfStreamingParams{ |
| CiphertextSegmentSize: ciphertextSegmentSize, |
| DerivedKeySize: derivedKeySize, |
| HkdfHashType: hkdfHashType, |
| }, |
| } |
| } |
| |
| // NewAESCTRHMACKey creates a randomly generated AESCTRHMACKey. |
| func NewAESCTRHMACKey(keyVersion, keySize uint32, hkdfHashType commonpb.HashType, derivedKeySize uint32, hashType commonpb.HashType, tagSize, ciphertextSegmentSize uint32) *ctrhmacpb.AesCtrHmacStreamingKey { |
| keyValue := random.GetRandomBytes(keySize) |
| return &ctrhmacpb.AesCtrHmacStreamingKey{ |
| Version: keyVersion, |
| KeyValue: keyValue, |
| Params: &ctrhmacpb.AesCtrHmacStreamingParams{ |
| CiphertextSegmentSize: ciphertextSegmentSize, |
| DerivedKeySize: derivedKeySize, |
| HkdfHashType: hkdfHashType, |
| HmacParams: &hmacpb.HmacParams{ |
| Hash: hashType, |
| TagSize: tagSize, |
| }, |
| }, |
| } |
| } |
| |
| // NewAESCTRHMACKeyFormat returns a new AESCTRHMACKeyFormat. |
| func NewAESCTRHMACKeyFormat(keySize uint32, hkdfHashType commonpb.HashType, derivedKeySize uint32, hashType commonpb.HashType, tagSize, ciphertextSegmentSize uint32) *ctrhmacpb.AesCtrHmacStreamingKeyFormat { |
| return &ctrhmacpb.AesCtrHmacStreamingKeyFormat{ |
| KeySize: keySize, |
| Params: &ctrhmacpb.AesCtrHmacStreamingParams{ |
| CiphertextSegmentSize: ciphertextSegmentSize, |
| DerivedKeySize: derivedKeySize, |
| HkdfHashType: hkdfHashType, |
| HmacParams: &hmacpb.HmacParams{ |
| Hash: hashType, |
| TagSize: tagSize, |
| }, |
| }, |
| } |
| } |
| |
| // NewHMACParams returns a new HMACParams. |
| func NewHMACParams(hashType commonpb.HashType, tagSize uint32) *hmacpb.HmacParams { |
| return &hmacpb.HmacParams{ |
| Hash: hashType, |
| TagSize: tagSize, |
| } |
| } |
| |
| // NewHMACKey creates a new HMACKey with the specified parameters. |
| func NewHMACKey(hashType commonpb.HashType, tagSize uint32) *hmacpb.HmacKey { |
| params := NewHMACParams(hashType, tagSize) |
| keyValue := random.GetRandomBytes(20) |
| return &hmacpb.HmacKey{ |
| Version: HMACKeyVersion, |
| Params: params, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewHMACKeyFormat creates a new HMACKeyFormat with the specified parameters. |
| func NewHMACKeyFormat(hashType commonpb.HashType, tagSize uint32) *hmacpb.HmacKeyFormat { |
| params := NewHMACParams(hashType, tagSize) |
| keySize := uint32(20) |
| return &hmacpb.HmacKeyFormat{ |
| Params: params, |
| KeySize: keySize, |
| } |
| } |
| |
| // NewAESCMACParams returns a new AESCMACParams. |
| func NewAESCMACParams(tagSize uint32) *cmacpb.AesCmacParams { |
| return &cmacpb.AesCmacParams{ |
| TagSize: tagSize, |
| } |
| } |
| |
| // NewAESCMACKey creates a new AESCMACKey with the specified parameters. |
| func NewAESCMACKey(tagSize uint32) *cmacpb.AesCmacKey { |
| params := NewAESCMACParams(tagSize) |
| keyValue := random.GetRandomBytes(32) |
| return &cmacpb.AesCmacKey{ |
| Version: AESCMACKeyVersion, |
| Params: params, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewAESCMACKeyFormat creates a new AESCMACKeyFormat with the specified parameters. |
| func NewAESCMACKeyFormat(tagSize uint32) *cmacpb.AesCmacKeyFormat { |
| params := NewAESCMACParams(tagSize) |
| keySize := uint32(32) |
| return &cmacpb.AesCmacKeyFormat{ |
| Params: params, |
| KeySize: keySize, |
| } |
| } |
| |
| // NewHMACKeysetManager returns a new KeysetManager that contains a HMACKey. |
| func NewHMACKeysetManager() *keyset.Manager { |
| ksm := keyset.NewManager() |
| kt := mac.HMACSHA256Tag128KeyTemplate() |
| keyID, err := ksm.Add(kt) |
| if err != nil { |
| panic(fmt.Sprintf("cannot add key: %v", err)) |
| } |
| err = ksm.SetPrimary(keyID) |
| if err != nil { |
| panic(fmt.Sprintf("cannot set primary key: %v", err)) |
| } |
| return ksm |
| } |
| |
| // NewHMACKeyData returns a new KeyData that contains a HMACKey. |
| func NewHMACKeyData(hashType commonpb.HashType, tagSize uint32) *tinkpb.KeyData { |
| key := NewHMACKey(hashType, tagSize) |
| serializedKey, err := proto.Marshal(key) |
| if err != nil { |
| log.Fatalf("failed serializing proto: %v", err) |
| } |
| return &tinkpb.KeyData{ |
| TypeUrl: HMACTypeURL, |
| Value: serializedKey, |
| KeyMaterialType: tinkpb.KeyData_SYMMETRIC, |
| } |
| } |
| |
| // NewHMACPRFParams returns a new HMACPRFParams. |
| func NewHMACPRFParams(hashType commonpb.HashType) *hmacprfpb.HmacPrfParams { |
| return &hmacprfpb.HmacPrfParams{ |
| Hash: hashType, |
| } |
| } |
| |
| // NewHMACPRFKey creates a new HMACPRFKey with the specified parameters. |
| func NewHMACPRFKey(hashType commonpb.HashType) *hmacprfpb.HmacPrfKey { |
| params := NewHMACPRFParams(hashType) |
| keyValue := random.GetRandomBytes(32) |
| return &hmacprfpb.HmacPrfKey{ |
| Version: HMACPRFKeyVersion, |
| Params: params, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewHMACPRFKeyFormat creates a new HMACPRFKeyFormat with the specified parameters. |
| func NewHMACPRFKeyFormat(hashType commonpb.HashType) *hmacprfpb.HmacPrfKeyFormat { |
| params := NewHMACPRFParams(hashType) |
| keySize := uint32(32) |
| return &hmacprfpb.HmacPrfKeyFormat{ |
| Params: params, |
| KeySize: keySize, |
| } |
| } |
| |
| // NewHKDFPRFParams returns a new HKDFPRFParams. |
| func NewHKDFPRFParams(hashType commonpb.HashType, salt []byte) *hkdfprfpb.HkdfPrfParams { |
| return &hkdfprfpb.HkdfPrfParams{ |
| Hash: hashType, |
| Salt: salt, |
| } |
| } |
| |
| // NewHKDFPRFKey creates a new HKDFPRFKey with the specified parameters. |
| func NewHKDFPRFKey(hashType commonpb.HashType, salt []byte) *hkdfprfpb.HkdfPrfKey { |
| params := NewHKDFPRFParams(hashType, salt) |
| keyValue := random.GetRandomBytes(32) |
| return &hkdfprfpb.HkdfPrfKey{ |
| Version: HKDFPRFKeyVersion, |
| Params: params, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewHKDFPRFKeyFormat creates a new HKDFPRFKeyFormat with the specified parameters. |
| func NewHKDFPRFKeyFormat(hashType commonpb.HashType, salt []byte) *hkdfprfpb.HkdfPrfKeyFormat { |
| params := NewHKDFPRFParams(hashType, salt) |
| keySize := uint32(32) |
| return &hkdfprfpb.HkdfPrfKeyFormat{ |
| Params: params, |
| KeySize: keySize, |
| } |
| } |
| |
| // NewAESCMACPRFKey creates a new AESCMACPRFKey with the specified parameters. |
| func NewAESCMACPRFKey() *aescmacprfpb.AesCmacPrfKey { |
| keyValue := random.GetRandomBytes(32) |
| return &aescmacprfpb.AesCmacPrfKey{ |
| Version: AESCMACPRFKeyVersion, |
| KeyValue: keyValue, |
| } |
| } |
| |
| // NewAESCMACPRFKeyFormat creates a new AESCMACPRFKeyFormat with the specified parameters. |
| func NewAESCMACPRFKeyFormat() *aescmacprfpb.AesCmacPrfKeyFormat { |
| keySize := uint32(32) |
| return &aescmacprfpb.AesCmacPrfKeyFormat{ |
| KeySize: keySize, |
| } |
| } |
| |
| // NewKeyData creates a new KeyData with the specified parameters. |
| func NewKeyData(typeURL string, value []byte, materialType tinkpb.KeyData_KeyMaterialType) *tinkpb.KeyData { |
| return &tinkpb.KeyData{ |
| TypeUrl: typeURL, |
| Value: value, |
| KeyMaterialType: materialType, |
| } |
| } |
| |
| // NewKey creates a new Key with the specified parameters. |
| func NewKey(keyData *tinkpb.KeyData, status tinkpb.KeyStatusType, keyID uint32, prefixType tinkpb.OutputPrefixType) *tinkpb.Keyset_Key { |
| return &tinkpb.Keyset_Key{ |
| KeyData: keyData, |
| Status: status, |
| KeyId: keyID, |
| OutputPrefixType: prefixType, |
| } |
| } |
| |
| // NewKeyset creates a new Keyset with the specified parameters. |
| func NewKeyset(primaryKeyID uint32, keys []*tinkpb.Keyset_Key) *tinkpb.Keyset { |
| return &tinkpb.Keyset{ |
| PrimaryKeyId: primaryKeyID, |
| Key: keys, |
| } |
| } |
| |
| // GenerateMutations generates different byte mutations for a given byte array. |
| func GenerateMutations(src []byte) (all [][]byte) { |
| // Flip bits |
| for i := 0; i < len(src); i++ { |
| for j := 0; j < 8; j++ { |
| n := make([]byte, len(src)) |
| copy(n, src) |
| n[i] = n[i] ^ (1 << uint8(j)) |
| all = append(all, n) |
| } |
| } |
| |
| //truncate bytes |
| for i := 1; i < len(src); i++ { |
| n := make([]byte, len(src[i:])) |
| copy(n, src[i:]) |
| all = append(all, n) |
| } |
| |
| //append extra byte |
| m := make([]byte, len(src)+1) |
| copy(m, src) |
| all = append(all, m) |
| return |
| } |
| |
| // ZTestUniformString uses a z test on the given byte string, expecting all |
| // bits to be uniformly set with probability 1/2. Returns non ok status if the |
| // z test fails by more than 10 standard deviations. |
| // |
| // With less statistics jargon: This counts the number of bits set and expects |
| // the number to be roughly half of the length of the string. The law of large |
| // numbers suggests that we can assume that the longer the string is, the more |
| // accurate that estimate becomes for a random string. This test is useful to |
| // detect things like strings that are entirely zero. |
| // |
| // Note: By itself, this is a very weak test for randomness. |
| func ZTestUniformString(bytes []byte) error { |
| expected := float64(len(bytes)) * 8.0 / 2.0 |
| stddev := math.Sqrt(float64(len(bytes)) * 8.0 / 4.0) |
| numSetBits := int64(0) |
| for _, b := range bytes { |
| // Counting the number of bits set in byte: |
| for b != 0 { |
| numSetBits++ |
| b = b & (b - 1) |
| } |
| } |
| // Check that the number of bits is within 10 stddevs. |
| if math.Abs(float64(numSetBits)-expected) < 10.0*stddev { |
| return nil |
| } |
| return fmt.Errorf("Z test for uniformly distributed variable out of bounds; "+ |
| "Actual number of set bits was %d expected was %0.00f, 10 * standard deviation is 10 * %0.00f = %0.00f", |
| numSetBits, expected, stddev, 10.0*stddev) |
| } |
| |
| func rotate(bytes []byte) []byte { |
| result := make([]byte, len(bytes)) |
| for i := 0; i < len(bytes); i++ { |
| prev := i |
| if i == 0 { |
| prev = len(bytes) |
| } |
| result[i] = (bytes[i] >> 1) | |
| (bytes[prev-1] << 7) |
| } |
| return result |
| } |
| |
| // ZTestCrosscorrelationUniformStrings tests that the crosscorrelation of two |
| // strings of equal length points to independent and uniformly distributed |
| // strings. Returns non ok status if the z test fails by more than 10 standard |
| // deviations. |
| // |
| // With less statistics jargon: This xors two strings and then performs the |
| // ZTestUniformString on the result. If the two strings are independent and |
| // uniformly distributed, the xor'ed string is as well. A cross correlation test |
| // will find whether two strings overlap more or less than it would be expected. |
| // |
| // Note: Having a correlation of zero is only a necessary but not sufficient |
| // condition for independence. |
| func ZTestCrosscorrelationUniformStrings(bytes1, bytes2 []byte) error { |
| if len(bytes1) != len(bytes2) { |
| return fmt.Errorf( |
| "Strings are not of equal length") |
| } |
| crossed := make([]byte, len(bytes1)) |
| for i := 0; i < len(bytes1); i++ { |
| crossed[i] = bytes1[i] ^ bytes2[i] |
| } |
| return ZTestUniformString(crossed) |
| } |
| |
| // ZTestAutocorrelationUniformString tests that the autocorrelation of a string |
| // points to the bits being independent and uniformly distributed. |
| // Rotates the string in a cyclic fashion. Returns non ok status if the z test |
| // fails by more than 10 standard deviations. |
| // |
| // With less statistics jargon: This rotates the string bit by bit and performs |
| // ZTestCrosscorrelationUniformStrings on each of the rotated strings and the |
| // original. This will find self similarity of the input string, especially |
| // periodic self similarity. For example, it is a decent test to find English |
| // text (needs about 180 characters with the current settings). |
| // |
| // Note: Having a correlation of zero is only a necessary but not sufficient |
| // condition for independence. |
| func ZTestAutocorrelationUniformString(bytes []byte) error { |
| rotated := make([]byte, len(bytes)) |
| copy(rotated, bytes) |
| violations := []string{} |
| for i := 1; i < len(bytes)*8; i++ { |
| rotated = rotate(rotated) |
| err := ZTestCrosscorrelationUniformStrings(bytes, rotated) |
| if err != nil { |
| violations = append(violations, strconv.Itoa(i)) |
| } |
| } |
| if len(violations) == 0 { |
| return nil |
| } |
| return fmt.Errorf("Autocorrelation exceeded 10 standard deviation at %d indices: %s", len(violations), strings.Join(violations, ", ")) |
| } |
| |
| // eciesAEADHKDFPublicKey returns a EciesAeadHkdfPublicKey with specified parameters. |
| func eciesAEADHKDFPublicKey(c commonpb.EllipticCurveType, ht commonpb.HashType, ptfmt commonpb.EcPointFormat, dekT *tinkpb.KeyTemplate, x, y, salt []byte) *eciespb.EciesAeadHkdfPublicKey { |
| return &eciespb.EciesAeadHkdfPublicKey{ |
| Version: 0, |
| Params: &eciespb.EciesAeadHkdfParams{ |
| KemParams: &eciespb.EciesHkdfKemParams{ |
| CurveType: c, |
| HkdfHashType: ht, |
| HkdfSalt: salt, |
| }, |
| DemParams: &eciespb.EciesAeadDemParams{ |
| AeadDem: dekT, |
| }, |
| EcPointFormat: ptfmt, |
| }, |
| X: x, |
| Y: y, |
| } |
| } |
| |
| // eciesAEADHKDFPrivateKey returns a EciesAeadHkdfPrivateKey with specified parameters |
| func eciesAEADHKDFPrivateKey(p *eciespb.EciesAeadHkdfPublicKey, d []byte) *eciespb.EciesAeadHkdfPrivateKey { |
| return &eciespb.EciesAeadHkdfPrivateKey{ |
| Version: 0, |
| PublicKey: p, |
| KeyValue: d, |
| } |
| } |
| |
| // GenerateECIESAEADHKDFPrivateKey generates a new EC key pair and returns the private key proto. |
| func GenerateECIESAEADHKDFPrivateKey(c commonpb.EllipticCurveType, ht commonpb.HashType, ptfmt commonpb.EcPointFormat, dekT *tinkpb.KeyTemplate, salt []byte) (*eciespb.EciesAeadHkdfPrivateKey, error) { |
| curve, err := subtlehybrid.GetCurve(c.String()) |
| if err != nil { |
| return nil, err |
| } |
| pvt, err := subtlehybrid.GenerateECDHKeyPair(curve) |
| if err != nil { |
| return nil, err |
| } |
| pubKey := eciesAEADHKDFPublicKey(c, ht, ptfmt, dekT, pvt.PublicKey.Point.X.Bytes(), pvt.PublicKey.Point.Y.Bytes(), salt) |
| //fmt.Println(proto.MarshalTextString(pubKey)) |
| return eciesAEADHKDFPrivateKey(pubKey, pvt.D.Bytes()), nil |
| } |