func eciesEncrypt(rand io.Reader, pub *ecdsa.PublicKey, s1, s2 []byte, plain []byte) ([]byte, error) { params := pub.Curve // Select an ephemeral elliptic curve key pair associated with // elliptic curve domain parameters params priv, Rx, Ry, err := elliptic.GenerateKey(pub.Curve, rand) //fmt.Printf("Rx %s\n", utils.EncodeBase64(Rx.Bytes())) //fmt.Printf("Ry %s\n", utils.EncodeBase64(Ry.Bytes())) // Convert R=(Rx,Ry) to an octed string R bar // This is uncompressed Rb := elliptic.Marshal(pub.Curve, Rx, Ry) // Derive a shared secret field element z from the ephemeral secret key k // and convert z to an octet string Z z, _ := params.ScalarMult(pub.X, pub.Y, priv) Z := z.Bytes() //fmt.Printf("Z %s\n", utils.EncodeBase64(Z)) // generate keying data K of length ecnKeyLen + macKeyLen octects from Z // ans s1 kE := make([]byte, 32) kM := make([]byte, 32) hkdf := hkdf.New(primitives.GetDefaultHash(), Z, s1, nil) _, err = hkdf.Read(kE) if err != nil { return nil, err } _, err = hkdf.Read(kM) if err != nil { return nil, err } // Use the encryption operation of the symmetric encryption scheme // to encrypt m under EK as ciphertext EM EM, err := aesEncrypt(kE, plain) // Use the tagging operation of the MAC scheme to compute // the tag D on EM || s2 mac := hmac.New(primitives.GetDefaultHash(), kM) mac.Write(EM) if len(s2) > 0 { mac.Write(s2) } D := mac.Sum(nil) // Output R,EM,D ciphertext := make([]byte, len(Rb)+len(EM)+len(D)) //fmt.Printf("Rb %s\n", utils.EncodeBase64(Rb)) //fmt.Printf("EM %s\n", utils.EncodeBase64(EM)) //fmt.Printf("D %s\n", utils.EncodeBase64(D)) copy(ciphertext, Rb) copy(ciphertext[len(Rb):], EM) copy(ciphertext[len(Rb)+len(EM):], D) return ciphertext, nil }
func (tca *TCA) calculatePreKey(variant []byte, preKey []byte) ([]byte, error) { mac := hmac.New(primitives.GetDefaultHash(), preKey) _, err := mac.Write(variant) if err != nil { return nil, err } return mac.Sum(nil), nil }
// 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, attributes []*pb.TCertAttribute) ([]pkix.Extension, map[string][]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. ks := make(map[string][]byte) extensions := make([]pkix.Extension, len(attributes)) // Compute preK_1 to encrypt attributes and enrollment ID preK_1, err := tcap.tca.getPreKFrom(enrollmentCert) if err != nil { return nil, nil, err } mac := hmac.New(primitives.GetDefaultHash(), preK_1) mac.Write(tcertid.Bytes()) preK_0 := mac.Sum(nil) // Compute encrypted EnrollmentID mac = hmac.New(primitives.GetDefaultHash(), preK_0) mac.Write([]byte("enrollmentID")) enrollmentIdKey := mac.Sum(nil)[:32] enrollmentID := []byte(enrollmentCert.Subject.CommonName) enrollmentID = append(enrollmentID, Padding...) encEnrollmentID, err := CBCEncrypt(enrollmentIdKey, enrollmentID) if err != nil { return nil, nil, err } // save k used to encrypt EnrollmentID ks["enrollmentId"] = enrollmentIdKey attributeIdentifierIndex := 9 count := 0 attributesHeader := make(map[string]int) // Encrypt and append attributes to the extensions slice for _, a := range attributes { count++ value := []byte(a.AttributeValue) //Save the position of the attribute extension on the header. attributesHeader[a.AttributeName] = count if viper.GetBool("tca.attribute-encryption.enabled") { mac = hmac.New(primitives.GetDefaultHash(), preK_0) mac.Write([]byte(a.AttributeName)) attributeKey := mac.Sum(nil)[:32] value = append(value, Padding...) value, err = CBCEncrypt(attributeKey, value) if err != nil { return nil, nil, err } // save k used to encrypt attribute ks[a.AttributeName] = attributeKey } // 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(attributes) > 0 { extensions = append(extensions, pkix.Extension{Id: TCertAttributesHeaders, Critical: false, Value: buildAttributesHeader(attributesHeader)}) } return extensions, ks, nil }
// CreateCertificateSet requests the creation of a new transaction certificate set by the TCA. func (tcap *TCAP) CreateCertificateSet(ctx context.Context, in *pb.TCertCreateSetReq) (*pb.TCertCreateSetResp, error) { Trace.Println("grpc TCAP:CreateCertificateSet") id := in.Id.Id raw, err := tcap.tca.eca.readCertificate(id, x509.KeyUsageDigitalSignature) 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]) 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 := CBCEncrypt(extKey, tidx) if err != nil { return nil, err } // TODO: We are storing each K used on the TCert in the ks array (the second return value of this call), but not returning it to the user. // We need to design a structure to return each TCert and the associated Ks. extensions, ks, err := tcap.generateExtensions(tcertid, encryptedTidx, cert, in.Attributes) if err != nil { return nil, err } spec := NewDefaultPeriodCertificateSpec(id, tcertid, &txPub, x509.KeyUsageDigitalSignature, extensions...) if raw, err = tcap.tca.createCertificateFromSpec(spec, in.Ts.Seconds, kdfKey); err != nil { Error.Println(err) return nil, err } set = append(set, &pb.TCert{raw, ks}) } return &pb.TCertCreateSetResp{&pb.CertSet{in.Ts, in.Id, kdfKey, set}}, nil }
// 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 }
func eciesDecrypt(priv *ecdsa.PrivateKey, s1, s2 []byte, ciphertext []byte) ([]byte, error) { params := priv.Curve var ( rLen int hLen = primitives.GetDefaultHash()().Size() mStart int mEnd int ) //fmt.Printf("Decrypt\n") switch ciphertext[0] { case 2, 3: rLen = ((priv.PublicKey.Curve.Params().BitSize + 7) / 8) + 1 if len(ciphertext) < (rLen + hLen + 1) { return nil, fmt.Errorf("Invalid ciphertext len [First byte = %d]", ciphertext[0]) } break case 4: rLen = 2*((priv.PublicKey.Curve.Params().BitSize+7)/8) + 1 if len(ciphertext) < (rLen + hLen + 1) { return nil, fmt.Errorf("Invalid ciphertext len [First byte = %d]", ciphertext[0]) } break default: return nil, fmt.Errorf("Invalid ciphertext. Invalid first byte. [%d]", ciphertext[0]) } mStart = rLen mEnd = len(ciphertext) - hLen //fmt.Printf("Rb %s\n", utils.EncodeBase64(ciphertext[:rLen])) Rx, Ry := elliptic.Unmarshal(priv.Curve, ciphertext[:rLen]) if Rx == nil { return nil, errors.New("Invalid ephemeral PK") } if !priv.Curve.IsOnCurve(Rx, Ry) { return nil, errors.New("Invalid point on curve") } //fmt.Printf("Rx %s\n", utils.EncodeBase64(Rx.Bytes())) //fmt.Printf("Ry %s\n", utils.EncodeBase64(Ry.Bytes())) // Derive a shared secret field element z from the ephemeral secret key k // and convert z to an octet string Z z, _ := params.ScalarMult(Rx, Ry, priv.D.Bytes()) Z := z.Bytes() //fmt.Printf("Z %s\n", utils.EncodeBase64(Z)) // generate keying data K of length ecnKeyLen + macKeyLen octects from Z // ans s1 kE := make([]byte, 32) kM := make([]byte, 32) hkdf := hkdf.New(primitives.GetDefaultHash(), Z, s1, nil) _, err := hkdf.Read(kE) if err != nil { return nil, err } _, err = hkdf.Read(kM) if err != nil { return nil, err } // Use the tagging operation of the MAC scheme to compute // the tag D on EM || s2 and then compare mac := hmac.New(primitives.GetDefaultHash(), kM) mac.Write(ciphertext[mStart:mEnd]) if len(s2) > 0 { mac.Write(s2) } D := mac.Sum(nil) //fmt.Printf("EM %s\n", utils.EncodeBase64(ciphertext[mStart:mEnd])) //fmt.Printf("D' %s\n", utils.EncodeBase64(D)) //fmt.Printf("D %s\n", utils.EncodeBase64(ciphertext[mEnd:])) if subtle.ConstantTimeCompare(ciphertext[mEnd:], D) != 1 { return nil, errors.New("Tag check failed") } // Use the decryption operation of the symmetric encryption scheme // to decryptr EM under EK as plaintext plaintext, err := aesDecrypt(kE, ciphertext[mStart:mEnd]) return plaintext, err }