func TestCBCPKCS7Encrypt_IVIsRandom(t *testing.T) { // Encrypt two times with same key. The first 16 bytes should be // different if IV is random. key := make([]byte, 32) rand.Reader.Read(key) t.Log("Key 1", key) var msg = []byte("a message to encrypt") cipher1, err := primitives.CBCPKCS7Encrypt(key, msg) if err != nil { t.Fatalf("Error encrypting the message.") } // expecting a different IV if same message is encrypted with same key cipher2, err := primitives.CBCPKCS7Encrypt(key, msg) if err != nil { t.Fatal("Error encrypting the message.") } iv1 := cipher1[:aes.BlockSize] iv2 := cipher2[:aes.BlockSize] t.Log("Cipher 1: ", iv1) t.Log("Cipher 2: ", iv2) t.Log("bytes.Equal: ", bytes.Equal(iv1, iv2)) if bytes.Equal(iv1, iv2) { t.Fatal("Error: ciphers contain identical initialisation vectors.") } }
// TestCBCPKCS7Encrypt_VerifyRandomIVs encrypts twice with same key. The first 16 bytes should be different if IV is generated randomly. func TestCBCPKCS7Encrypt_VerifyRandomIVs(t *testing.T) { key := make([]byte, aes.BlockSize) rand.Reader.Read(key) t.Log("Key 1", key) var ptext = []byte("a message to encrypt") ciphertext1, err := primitives.CBCPKCS7Encrypt(key, ptext) if err != nil { t.Fatalf("Error encrypting '%s': %s", ptext, err) } // Expecting a different IV if same message is encrypted with same key ciphertext2, err := primitives.CBCPKCS7Encrypt(key, ptext) if err != nil { t.Fatalf("Error encrypting '%s': %s", ptext, err) } iv1 := ciphertext1[:aes.BlockSize] iv2 := ciphertext2[:aes.BlockSize] t.Log("Ciphertext1: ", iv1) t.Log("Ciphertext2: ", iv2) t.Log("bytes.Equal: ", bytes.Equal(iv1, iv2)) if bytes.Equal(iv1, iv2) { t.Fatal("Error: ciphertexts contain identical initialization vectors (IVs)") } }
func TestCBCPKCS7EncryptCBCPKCS7Decrypt(t *testing.T) { // Encrypt with CBCPKCS7Encrypt and Decrypt with CBCPKCS7Decrypt // The purpose of this test is not to test the implementation of the AES standard // library but to verify the code wrapping/unwrapping the AES cipher. key := make([]byte, primitives.AESKeyLength) rand.Reader.Read(key) var msg = []byte("a message with arbitrary length (42 bytes)") encrypted, encErr := primitives.CBCPKCS7Encrypt(key, msg) if encErr != nil { t.Fatalf("Error encrypting message %v", encErr) } decrypted, dErr := primitives.CBCPKCS7Decrypt(key, encrypted) if dErr != nil { t.Fatalf("Error encrypting message %v", dErr) } if string(msg[:]) != string(decrypted[:]) { t.Fatalf("Decrypt( Encrypt(msg) ) != msg: Ciphertext decryption with the same key must restore the original message!") } }
// TestAESRelatedUtilFunctions tests various functions commonly used in fabric wrt AES func TestAESRelatedUtilFunctions(t *testing.T) { key, err := primitives.GenAESKey() if err != nil { t.Fatalf("Failed generating AES key [%s]", err) } for i := 1; i < 100; i++ { len, err := rand.Int(rand.Reader, big.NewInt(1024)) if err != nil { t.Fatalf("Failed generating AES key [%s]", err) } msg, err := primitives.GetRandomBytes(int(len.Int64()) + 1) if err != nil { t.Fatalf("Failed generating AES key [%s]", err) } ct, err := primitives.CBCPKCS7Encrypt(key, msg) if err != nil { t.Fatalf("Failed encrypting [%s]", err) } msg2, err := primitives.CBCPKCS7Decrypt(key, ct) if err != nil { t.Fatalf("Failed decrypting [%s]", err) } if 0 != bytes.Compare(msg, msg2) { t.Fatalf("Wrong decryption output [%x][%x]", msg, msg2) } } }
// TestCBCPKCS7EncryptCBCPKCS7Decrypt encrypts using CBCPKCS7Encrypt and decrypts using CBCPKCS7Decrypt. func TestCBCPKCS7EncryptCBCPKCS7Decrypt(t *testing.T) { // Note: The purpose of this test is not to test AES-256 in CBC mode's strength // ... but rather to verify the code wrapping/unwrapping the cipher. key := make([]byte, primitives.AESKeyLength) rand.Reader.Read(key) // 123456789012345678901234567890123456789012 var ptext = []byte("a message with arbitrary length (42 bytes)") encrypted, encErr := primitives.CBCPKCS7Encrypt(key, ptext) if encErr != nil { t.Fatalf("Error encrypting '%s': %s", ptext, encErr) } decrypted, dErr := primitives.CBCPKCS7Decrypt(key, encrypted) if dErr != nil { t.Fatalf("Error decrypting the encrypted '%s': %v", ptext, dErr) } if string(ptext[:]) != string(decrypted[:]) { t.Fatal("Decrypt( Encrypt( ptext ) ) != ptext: Ciphertext decryption with the same key must result in the original plaintext!") } }
// TestCBCPKCS7Encrypt_EmptyPlaintext encrypts and pad an empty ptext. Verifying as well that the ciphertext length is as expected. func TestCBCPKCS7Encrypt_EmptyPlaintext(t *testing.T) { key := make([]byte, primitives.AESKeyLength) rand.Reader.Read(key) t.Log("Generated key: ", key) var emptyPlaintext = []byte("") t.Log("Plaintext length: ", len(emptyPlaintext)) ciphertext, encErr := primitives.CBCPKCS7Encrypt(key, emptyPlaintext) if encErr != nil { t.Fatalf("Error encrypting '%v'", encErr) } // Expected ciphertext length: primitives.AESKeyLength (=32) // As part of the padding, at least one block gets encrypted (while the first block is the IV) const expectedLength = aes.BlockSize + aes.BlockSize if len(ciphertext) != expectedLength { t.Fatalf("Wrong ciphertext length. Expected %d, recieved %d", expectedLength, len(ciphertext)) } t.Log("Ciphertext length: ", len(ciphertext)) t.Log("Cipher: ", ciphertext) }
// TestCBCPKCS7EncryptCBCDecrypt_ExpectingCorruptMessage verifies that CBCDecrypt can decrypt the unpadded // version of the ciphertext, of a message of BlockSize length. func TestCBCPKCS7EncryptCBCDecrypt_ExpectingCorruptMessage(t *testing.T) { // One of the purposes of this test is to also document and clarify the expected behavior, i.e., that an extra // block is appended to the message at the padding stage, as per the spec of PKCS#7 v1.5 [see RFC-2315 p.21] key := make([]byte, primitives.AESKeyLength) rand.Reader.Read(key) // 0123456789ABCDEF var ptext = []byte("a 16 byte messag") encrypted, encErr := primitives.CBCPKCS7Encrypt(key, ptext) if encErr != nil { t.Fatalf("Error encrypting ptext %v", encErr) } decrypted, dErr := primitives.CBCDecrypt(key, encrypted) if dErr != nil { t.Fatalf("Error encrypting ptext %v, %v", dErr, decrypted) } if string(ptext[:]) != string(decrypted[:aes.BlockSize]) { t.Log("ptext: ", ptext) t.Log("decrypted: ", decrypted[:aes.BlockSize]) t.Fatal("Encryption->Decryption with same key should result in original ptext") } if !bytes.Equal(decrypted[aes.BlockSize:], bytes.Repeat([]byte{byte(aes.BlockSize)}, aes.BlockSize)) { t.Fatal("Expected extra block with padding in encrypted ptext", decrypted) } }
func TestCBCPKCS7Encrypt_EmptyText(t *testing.T) { // Encrypt an empty message. Mainly to document // a borderline case. Checking as well that the // cipher length is as expected. key := make([]byte, 32) rand.Reader.Read(key) t.Log("Generated key: ", key) var msg = []byte("") t.Log("Message length: ", len(msg)) cipher, encErr := primitives.CBCPKCS7Encrypt(key, msg) if encErr != nil { t.Fatalf("Error encrypting message %v", encErr) } t.Log("Cipher length: ", len(cipher)) // expected cipher length: 32 // with padding, at least one block gets encrypted // the first block is the IV var expectedLength = aes.BlockSize + aes.BlockSize if len(cipher) != expectedLength { t.Fatalf("Cipher length is wrong. Expected %d, got %d", expectedLength, len(cipher)) } t.Log("Cipher: ", cipher) }
func (client *clientImpl) encryptTxVersion1_1(tx *obc.Transaction) error { // client.enrollChainKey is an AES key represented as byte array enrollChainKey := client.enrollChainKey.([]byte) // Derive key txKey := primitives.HMAC(enrollChainKey, tx.Nonce) // client.log.Info("Deriving from :", utils.EncodeBase64(client.node.enrollChainKey)) // client.log.Info("Nonce ", utils.EncodeBase64(tx.Nonce)) // client.log.Info("Derived key ", utils.EncodeBase64(txKey)) // Encrypt Payload payloadKey := primitives.HMACAESTruncated(txKey, []byte{1}) encryptedPayload, err := primitives.CBCPKCS7Encrypt(payloadKey, tx.Payload) if err != nil { return err } tx.Payload = encryptedPayload // Encrypt ChaincodeID chaincodeIDKey := primitives.HMACAESTruncated(txKey, []byte{2}) encryptedChaincodeID, err := primitives.CBCPKCS7Encrypt(chaincodeIDKey, tx.ChaincodeID) if err != nil { return err } tx.ChaincodeID = encryptedChaincodeID // Encrypt Metadata if len(tx.Metadata) != 0 { metadataKey := primitives.HMACAESTruncated(txKey, []byte{3}) encryptedMetadata, err := primitives.CBCPKCS7Encrypt(metadataKey, tx.Metadata) if err != nil { return err } tx.Metadata = encryptedMetadata } return nil }
func TestCBCPKCS7EncryptCBCDecrypt_ExpectingCorruptMessage(t *testing.T) { // When encrypting a message that does not need padding, i.e. a message // whose length is a multiple of the block size, with CBCPKCS7Encrypt, it // can be decrypted with CBCDecrypt but the returned message is corrupted. // // The intend of this test is to document this behaviour for clarity. // // The reason is that the section 10.3 Note 2 in #PKCS7 states that // an extra block is appended to the message for padding. Since this // extra block is added when using CBCPKCS7Encrypt for encryption, // CBCDecrypt returns the original message plus this extra block. // // Note: // the same applies for messages of arbitrary length. key := make([]byte, 32) rand.Reader.Read(key) // 0123456789ABCDEF var msg = []byte("a 16 byte messag") encrypted, encErr := primitives.CBCPKCS7Encrypt(key, msg) if encErr != nil { t.Fatalf("Error encrypting message %v", encErr) } decrypted, dErr := primitives.CBCDecrypt(key, encrypted) if dErr != nil { t.Fatalf("Error encrypting message %v, %v", dErr, decrypted) } if string(msg[:]) != string(decrypted[:aes.BlockSize]) { t.Log("msg: ", msg) t.Log("decrypted: ", decrypted[:aes.BlockSize]) t.Fatal("Encryption->Decryption with same key should result in original message") } if !bytes.Equal(decrypted[aes.BlockSize:], bytes.Repeat([]byte{byte(aes.BlockSize)}, aes.BlockSize)) { t.Fatal("Expected extra block with padding in encrypted message", decrypted) } }
// TestCBCPKCS7Encrypt_CorrectCiphertextLengthCheck verifies that the returned ciphertext lengths are as expected. func TestCBCPKCS7Encrypt_CorrectCiphertextLengthCheck(t *testing.T) { key := make([]byte, aes.BlockSize) rand.Reader.Read(key) // length of message (in bytes) == aes.BlockSize (16 bytes) // The expected cipher length = IV length (1 block) + 1 block message var ptext = []byte("0123456789ABCDEF") for i := 1; i < aes.BlockSize; i++ { ciphertext, err := primitives.CBCPKCS7Encrypt(key, ptext[:i]) if err != nil { t.Fatal("Error encrypting '", ptext, "'") } expectedLength := aes.BlockSize + aes.BlockSize if len(ciphertext) != expectedLength { t.Fatalf("Incorrect ciphertext incorrect: expected '%d', received '%d'", expectedLength, len(ciphertext)) } } }
func TestCBCPKCS7Encrypt_CipherLengthCorrect(t *testing.T) { // Check that the cipher lengths are as expected. key := make([]byte, 32) rand.Reader.Read(key) // length of message < aes.BlockSize (16 bytes) // --> expected cipher length = IV length (1 block) + 1 block message // = var msg = []byte("0123456789ABCDEF") for i := 1; i < aes.BlockSize; i++ { cipher, err := primitives.CBCPKCS7Encrypt(key, msg[:i]) if err != nil { t.Fatal("Error encrypting the message.", cipher) } expectedLength := aes.BlockSize + aes.BlockSize if len(cipher) != expectedLength { t.Fatalf("Cipher length incorrect: expected %d, got %d", expectedLength, len(cipher)) } } }
//EncryptAttributeValue encrypts "attributeValue" using "attributeKey" func EncryptAttributeValue(attributeKey []byte, attributeValue []byte) ([]byte, error) { value := append(attributeValue, padding...) return primitives.CBCPKCS7Encrypt(attributeKey, value) }
// Generate encrypted extensions to be included into the TCert (TCertIndex, EnrollmentID and attributes). func (tcap *TCAP) generateExtensions(tcertid *big.Int, tidx []byte, enrollmentCert *x509.Certificate, attrs []*pb.ACAAttribute) ([]pkix.Extension, []byte, error) { // For each TCert we need to store and retrieve to the user the list of Ks used to encrypt the EnrollmentID and the attributes. extensions := make([]pkix.Extension, len(attrs)) // Compute preK_1 to encrypt attributes and enrollment ID preK1, err := tcap.tca.getPreKFrom(enrollmentCert) if err != nil { return nil, nil, err } mac := hmac.New(primitives.GetDefaultHash(), preK1) mac.Write(tcertid.Bytes()) preK0 := mac.Sum(nil) // Compute encrypted EnrollmentID mac = hmac.New(primitives.GetDefaultHash(), preK0) mac.Write([]byte("enrollmentID")) enrollmentIDKey := mac.Sum(nil)[:32] enrollmentID := []byte(enrollmentCert.Subject.CommonName) enrollmentID = append(enrollmentID, Padding...) encEnrollmentID, err := primitives.CBCPKCS7Encrypt(enrollmentIDKey, enrollmentID) if err != nil { return nil, nil, err } attributeIdentifierIndex := 9 count := 0 attrsHeader := make(map[string]int) // Encrypt and append attrs to the extensions slice for _, a := range attrs { count++ value := []byte(a.AttributeValue) //Save the position of the attribute extension on the header. attrsHeader[a.AttributeName] = count if isEnabledAttributesEncryption() { value, err = attributes.EncryptAttributeValuePK0(preK0, a.AttributeName, value) if err != nil { return nil, nil, err } } // Generate an ObjectIdentifier for the extension holding the attribute TCertEncAttributes := asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6, attributeIdentifierIndex + count} // Add the attribute extension to the extensions array extensions[count-1] = pkix.Extension{Id: TCertEncAttributes, Critical: false, Value: value} } // Append the TCertIndex to the extensions extensions = append(extensions, pkix.Extension{Id: TCertEncTCertIndex, Critical: true, Value: tidx}) // Append the encrypted EnrollmentID to the extensions extensions = append(extensions, pkix.Extension{Id: TCertEncEnrollmentID, Critical: false, Value: encEnrollmentID}) // Append the attributes header if there was attributes to include in the TCert if len(attrs) > 0 { headerValue, err := attributes.BuildAttributesHeader(attrsHeader) if err != nil { return nil, nil, err } if isEnabledAttributesEncryption() { headerValue, err = attributes.EncryptAttributeValuePK0(preK0, attributes.HeaderAttributeName, headerValue) if err != nil { return nil, nil, err } } extensions = append(extensions, pkix.Extension{Id: TCertAttributesHeaders, Critical: false, Value: headerValue}) } return extensions, preK0, nil }
func (tcap *TCAP) createCertificateSet(ctx context.Context, raw []byte, in *pb.TCertCreateSetReq) (*pb.TCertCreateSetResp, error) { var attrs = []*pb.ACAAttribute{} var err error var id = in.Id.Id var timestamp = in.Ts.Seconds const TCERT_SUBJECT_COMMON_NAME_VALUE string = "Transaction Certificate" if in.Attributes != nil && viper.GetBool("aca.enabled") { attrs, err = tcap.requestAttributes(id, raw, in.Attributes) if err != nil { return nil, err } } cert, err := x509.ParseCertificate(raw) if err != nil { return nil, err } pub := cert.PublicKey.(*ecdsa.PublicKey) r, s := big.NewInt(0), big.NewInt(0) r.UnmarshalText(in.Sig.R) s.UnmarshalText(in.Sig.S) //sig := in.Sig in.Sig = nil hash := primitives.NewHash() raw, _ = proto.Marshal(in) hash.Write(raw) if ecdsa.Verify(pub, hash.Sum(nil), r, s) == false { return nil, errors.New("signature does not verify") } // Generate nonce for TCertIndex nonce := make([]byte, 16) // 8 bytes rand, 8 bytes timestamp rand.Reader.Read(nonce[:8]) binary.LittleEndian.PutUint64(nonce[8:], uint64(in.Ts.Seconds)) mac := hmac.New(primitives.GetDefaultHash(), tcap.tca.hmacKey) raw, _ = x509.MarshalPKIXPublicKey(pub) mac.Write(raw) kdfKey := mac.Sum(nil) num := int(in.Num) if num == 0 { num = 1 } // the batch of TCerts var set []*pb.TCert for i := 0; i < num; i++ { tcertid := util.GenerateIntUUID() // Compute TCertIndex tidx := []byte(strconv.Itoa(2*i + 1)) tidx = append(tidx[:], nonce[:]...) tidx = append(tidx[:], Padding...) mac := hmac.New(primitives.GetDefaultHash(), kdfKey) mac.Write([]byte{1}) extKey := mac.Sum(nil)[:32] mac = hmac.New(primitives.GetDefaultHash(), kdfKey) mac.Write([]byte{2}) mac = hmac.New(primitives.GetDefaultHash(), mac.Sum(nil)) mac.Write(tidx) one := new(big.Int).SetInt64(1) k := new(big.Int).SetBytes(mac.Sum(nil)) k.Mod(k, new(big.Int).Sub(pub.Curve.Params().N, one)) k.Add(k, one) tmpX, tmpY := pub.ScalarBaseMult(k.Bytes()) txX, txY := pub.Curve.Add(pub.X, pub.Y, tmpX, tmpY) txPub := ecdsa.PublicKey{Curve: pub.Curve, X: txX, Y: txY} // Compute encrypted TCertIndex encryptedTidx, err := primitives.CBCPKCS7Encrypt(extKey, tidx) if err != nil { return nil, err } extensions, preK0, err := tcap.generateExtensions(tcertid, encryptedTidx, cert, attrs) if err != nil { return nil, err } spec := NewDefaultPeriodCertificateSpecWithCommonName(id, TCERT_SUBJECT_COMMON_NAME_VALUE, tcertid, &txPub, x509.KeyUsageDigitalSignature, extensions...) if raw, err = tcap.tca.createCertificateFromSpec(spec, timestamp, kdfKey, false); err != nil { Error.Println(err) return nil, err } set = append(set, &pb.TCert{Cert: raw, Prek0: preK0}) } tcap.tca.persistCertificateSet(id, timestamp, nonce, kdfKey) return &pb.TCertCreateSetResp{Certs: &pb.CertSet{Ts: in.Ts, Id: in.Id, Key: kdfKey, Certs: set}}, nil }