// expandKey uses HKDF on SHA256 to create 256 bit random keys // from cryptographically secure masterkey and salt. func expandKey(masterkey []byte, nonsecretsalt []byte, count int) (keys [][]byte, err error) { hkdf := hkdf.New(sha256.New, masterkey, nonsecretsalt, []byte("Why not mix it up?")) // Generate keys keys = make([][]byte, count) for i := 0; i < count; i++ { keys[i] = make([]byte, 32) n, err := io.ReadFull(hkdf, keys[i]) if err == nil && n != 32 { err = fmt.Errorf("expandKey: HKDF did not return 32 byte key. Len: %d\n", len(keys[i])) } if err != nil { return nil, err } } // Check for obvious leakage or non-randomness for i := 0; i < count; i++ { if bytes.Contains(keys[i], masterkey) { err = fmt.Errorf("expandKey: HKDF failed") return nil, err } for j := 0; j < i; j++ { if bytes.Equal(keys[i], keys[j]) { err = fmt.Errorf("expandKey: HKDF failed") return nil, err } } } return keys, nil }
// Initializes a stream into an encrypted tunnel link. func (c *Connection) initClientTunnel(strm *stream.Stream, remote uint64, id uint64, key []byte, deadline time.Time) (*link.Link, error) { // Set a socket deadline for finishing the handshake strm.Sock().SetDeadline(deadline) defer strm.Sock().SetDeadline(time.Time{}) // Send the unencrypted tunnel id to associate with the remote tunnel init := &initPacket{ConnId: remote, TunId: id} if err := strm.Send(init); err != nil { return nil, err } // Create the encrypted link and authorize it hasher := func() hash.Hash { return config.HkdfHash.New() } hkdf := hkdf.New(hasher, key, config.HkdfSalt, config.HkdfInfo) conn := link.New(strm, hkdf, false) // Send and retrieve an authorization to verify both directions auth := &proto.Message{ Head: proto.Header{ Meta: &authPacket{Id: id}, }, } if err := conn.SendDirect(auth); err != nil { return nil, err } if msg, err := conn.RecvDirect(); err != nil { return nil, err } else if auth, ok := msg.Head.Meta.(*authPacket); !ok || auth.Id != id { return nil, errors.New("protocol violation") } conn.Start(config.IrisTunnelBuffer) // Return the initialized link return conn, nil }
// Extracts a usable sized symmetric key and IV for the stream cipher from the huge master key, and // creates a CTR stream cipher. func (s *Session) makeCipher() (cipher.Stream, error) { // Create the key derivation function hasher := func() hash.Hash { return s.hash.New() } hkdf := hkdf.New(hasher, s.secret.Bytes(), hkdfSalt, hkdfInfo) // Extract the symmetric key key := make([]byte, s.keybits/8) n, err := io.ReadFull(hkdf, key) if n != len(key) || err != nil { return nil, err } // Create the block cipher block, err := s.crypter(key) if err != nil { return nil, err } // Extract the IV for the counter mode iv := make([]byte, block.BlockSize()) n, err = io.ReadFull(hkdf, iv) if n != len(iv) || err != nil { return nil, err } // Create the stream cipher return cipher.NewCTR(block, iv), nil }
// split is the final wrap-up act to be executed at the end of a succesful // three act handshake. This function creates to internal cipherState // instances: one which is used to encrypt messages from the initiator to the // responder, and another which is used to encrypt message for the opposite // direction. func (b *BrontideMachine) split() { var ( empty []byte sendKey [32]byte recvKey [32]byte ) h := hkdf.New(sha256.New, b.chainingKey[:], empty, empty) // If we're the initiator the the frist 32 bytes are used to encrypt // our messages and the second 32-bytes to decrypt their messages. For // the responder the opposite is true. if b.initiator { h.Read(sendKey[:]) b.sendCipher = cipherState{} b.sendCipher.InitializeKey(sendKey) h.Read(recvKey[:]) b.recvCipher = cipherState{} b.recvCipher.InitializeKey(recvKey) } else { h.Read(recvKey[:]) b.recvCipher = cipherState{} b.recvCipher.InitializeKey(recvKey) h.Read(sendKey[:]) b.sendCipher = cipherState{} b.sendCipher.InitializeKey(sendKey) } }
// Derive uses HKDF with HMAC-SHA256 to derive key bytes in its material // parameter. func (d *Deriver) Derive(salt, context, material []byte) error { f := hkdf.New(sha256.New, d.secret, salt, context) if _, err := f.Read(material); err != nil { return err } return nil }
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 calculateSignatureSecret(secret []byte) ([]byte, error) { signatureSecretHkdf := hkdf.New(sha256.New, []byte(secret), nil, []byte(HKDF_INFO_SIGNING)) signatureSecret := make([]byte, sha256.Size) if _, err := io.ReadFull(signatureSecretHkdf, signatureSecret); err != nil { return nil, err } return signatureSecret, nil }
// Creates a new, double link session for authenticated data transfer. The // initiator is used to decide the key derivation order for the channels. func newSession(conn *stream.Stream, secret []byte, server bool) *Session { // Create the key derivation function hasher := func() hash.Hash { return config.HkdfHash.New() } hkdf := hkdf.New(hasher, secret, config.HkdfSalt, config.HkdfInfo) // Create the encrypted control link return &Session{ kdf: hkdf, CtrlLink: link.New(conn, hkdf, server), } }
// Initializes a stream into an encrypted tunnel link. func (o *Overlay) initServerTunnel(strm *stream.Stream) error { // Set a socket deadline for finishing the handshake strm.Sock().SetDeadline(time.Now().Add(config.IrisTunnelInitTimeout)) defer strm.Sock().SetDeadline(time.Time{}) // Fetch the unencrypted client initiator init := new(initPacket) if err := strm.Recv(init); err != nil { return err } o.lock.RLock() c, ok := o.conns[init.ConnId] o.lock.RUnlock() if !ok { return errors.New("connection not found") } c.tunLock.RLock() tun, ok := c.tunLive[init.TunId] c.tunLock.RUnlock() if !ok { return errors.New("tunnel not found") } // Create the encrypted link hasher := func() hash.Hash { return config.HkdfHash.New() } hkdf := hkdf.New(hasher, tun.secret, config.HkdfSalt, config.HkdfInfo) conn := link.New(strm, hkdf, true) // Send and retrieve an authorization to verify both directions auth := &proto.Message{ Head: proto.Header{ Meta: &authPacket{Id: tun.id}, }, } if err := conn.SendDirect(auth); err != nil { return err } if msg, err := conn.RecvDirect(); err != nil { return err } else if auth, ok := msg.Head.Meta.(*authPacket); !ok || auth.Id != tun.id { return errors.New("protocol violation") } conn.Start(config.IrisTunnelBuffer) // Send back the initialized link to the pending tunnel select { case tun.initDone <- conn: // Connection handled by initiator return nil case <-tun.initStop: // Initiator timed out or terminated, close conn.Close() return nil // No error, since tunnel was handled, albeit not as expected } }
func generateDerivedSecret(secret []byte, salt string, encodedTokenSecret string) (string, error) { derivedHkdf := hkdf.New(sha256.New, []byte(secret), []byte(salt), []byte(HKDF_INFO_DERIVE+encodedTokenSecret)) derivedSecret := make([]byte, sha256.Size) _, err := io.ReadFull(derivedHkdf, derivedSecret) if err != nil { return "", err } return base64.URLEncoding.EncodeToString(derivedSecret), nil }
// Kdf extracts and expands KEY_SEED via HKDF-SHA256 and returns `okm_len` bytes // of key material. func Kdf(keySeed []byte, okmLen int) []byte { kdf := hkdf.New(sha256.New, keySeed, tKey, mExpand) okm := make([]byte, okmLen) n, err := io.ReadFull(kdf, okm) if err != nil { panic(fmt.Sprintf("BUG: Failed HKDF: %s", err.Error())) } else if n != len(okm) { panic(fmt.Sprintf("BUG: Got truncated HKDF output: %d", n)) } return okm }
// Sha512 returns a 256-bit key func Sha512(master, salt, info []byte) ([32]byte, error) { hash := sha512.New hkdf := hkdf.New(hash, master, salt, info) key := make([]byte, 32) // 256 bit _, err := io.ReadFull(hkdf, key) var result [32]byte copy(result[:], key) return result, err }
// DeriveSecrets derives the requested number of bytes using HKDF, given // the inputKeyMaterial, salt and the info func DeriveSecrets(inputKeyMaterial, salt, info []byte, size int) ([]byte, error) { hkdf := hkdf.New(sha256.New, inputKeyMaterial, salt, info) secrets := make([]byte, size) n, err := io.ReadFull(hkdf, secrets) if err != nil { return nil, err } if n != size { return nil, err } return secrets, nil }
// XXX TODO: return err if init() or Reset() has not been called func (skgen *SecretKeyGen) Read(p []byte) (n int, err error) { prng := make([]byte, 256) n, err = io.ReadFull(rand.Reader, prng) if err != nil { //fmt.Fprintf(os.Stderr, "POUET POUET PROUT Error") //fmt.Println(err) return n, err } my_hkdf := hkdf.New(skgen.hash, skgen.input_pbkdf, prng, skgen.info_hkdf) n, err = io.ReadFull(my_hkdf, p) return n, err }
// DeriveKey is used to derive the encryption key that should be used depending // on the policy. If derivation is disabled the raw key is used and no context // is required, otherwise the KDF mode is used with the context to derive the // proper key. func (p *policy) DeriveKey(context []byte, ver int) ([]byte, error) { if !p.Type.DerivationSupported() { return nil, errutil.UserError{Err: fmt.Sprintf("derivation not supported for key type %v", p.Type)} } if p.Keys == nil || p.LatestVersion == 0 { return nil, errutil.InternalError{Err: "unable to access the key; no key versions found"} } if ver <= 0 || ver > p.LatestVersion { return nil, errutil.UserError{Err: "invalid key version"} } // Fast-path non-derived keys if !p.Derived { return p.Keys[ver].AESKey, nil } // Ensure a context is provided if len(context) == 0 { return nil, errutil.UserError{Err: "missing 'context' for key deriviation. The key was created using a derived key, which means additional, per-request information must be included in order to encrypt or decrypt information"} } switch p.KDF { case kdf_hmac_sha256_counter: prf := kdf.HMACSHA256PRF prfLen := kdf.HMACSHA256PRFLen return kdf.CounterMode(prf, prfLen, p.Keys[ver].AESKey, context, 256) case kdf_hkdf_sha256: reader := hkdf.New(sha256.New, p.Keys[ver].AESKey, nil, context) derBytes := bytes.NewBuffer(nil) derBytes.Grow(32) limReader := &io.LimitedReader{ R: reader, N: 32, } n, err := derBytes.ReadFrom(limReader) if err != nil { return nil, errutil.InternalError{Err: fmt.Sprintf("error reading returned derived bytes: %v", err)} } if n != 32 { return nil, errutil.InternalError{Err: fmt.Sprintf("unable to read enough derived bytes, needed 32, got %d", n)} } return derBytes.Bytes(), nil default: return nil, errutil.InternalError{Err: "unsupported key derivation mode"} } }
// First argument is the algorithm used. "plain" (AlgoPlain) and // "dh-ietf1024-sha256-aes128-cbc-pkcs7" (AlgoDH) are supported. // // The dbus api has the caller supply their DH public key and returns // the other side's public key, but this implementation generates a // new keypair, does the exchange, derives the encryption key, and then // stores it in the returned Session. func (s Service) OpenSession(algo string, args ...interface{}) (Session, error) { // spec: OpenSession(IN String algorithm, IN Variant input, OUT Variant output, OUT ObjectPath result); var ret Session conn, err := dbus.SessionBus() if err != nil { return ret, err } switch algo { case AlgoPlain: var discard dbus.Variant var sessionPath dbus.ObjectPath err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant("")).Store(&discard, &sessionPath) if err != nil { return ret, err } ret = Session{conn.Object(ServiceName, sessionPath), algo, nil} case AlgoDH: // see http://standards.freedesktop.org/secret-service/ch07s03.html var sessionPath dbus.ObjectPath var srvReply dbus.Variant var srvPub []byte symKey := make([]byte, aes.BlockSize) grp, err := dhkx.GetGroup(2) if err != nil { return ret, err } privKey, err := grp.GeneratePrivateKey(rand.Reader) if err != nil { return ret, err } err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant(privKey.Bytes())).Store(&srvReply, &sessionPath) if err != nil { return ret, err } srvPub = srvReply.Value().([]byte) sharedKey, err := grp.ComputeKey(dhkx.NewPublicKey(srvPub), privKey) if err != nil { return ret, err } _, err = io.ReadFull(hkdf.New(sha256.New, sharedKey.Bytes(), nil, nil), symKey) ret = Session{conn.Object(ServiceName, sessionPath), algo, symKey} default: err = InvalidAlgorithm } return ret, err }
// mixKey is implements a basic HKDF-based key rachet. This method is called // with the result of each DH output generated during the handshake process. // The first 32 bytes extract from the HKDF reader is the next chaining key, // then latter 32 bytes become the temp secret key using within any future AEAD // operations until another DH operation is performed. func (s *symmetricState) mixKey(input []byte) { var info []byte secret := input salt := s.chainingKey h := hkdf.New(sha256.New, secret, salt[:], info) // hkdf(input, ck, zero) // | // | \ // | \ // ck k h.Read(s.chainingKey[:]) h.Read(s.tempKey[:]) // cipher.k = temp_key s.InitializeKey(s.tempKey) }
// deriveElkremRoot derives an elkrem root unique to a channel given the // private key for our public key in the 2-of-2 multi-sig, and the remote // node's multi-sig public key. The root is derived using the HKDF[1][2] // instantiated with sha-256. The secret data used is our multi-sig private // key, with the salt being the remote node's public key. // // [1]: https://eprint.iacr.org/2010/264.pdf // [2]: https://tools.ietf.org/html/rfc5869 func deriveElkremRoot(elkremDerivationRoot *btcec.PrivateKey, localMultiSigKey *btcec.PublicKey, remoteMultiSigKey *btcec.PublicKey) wire.ShaHash { secret := elkremDerivationRoot.Serialize() salt := localMultiSigKey.SerializeCompressed() info := remoteMultiSigKey.SerializeCompressed() rootReader := hkdf.New(sha256.New, secret, salt, info) // It's safe to ignore the error her as we know for sure that we won't // be draining the HKDF past its available entropy horizon. // TODO(roasbeef): revisit... var elkremRoot wire.ShaHash rootReader.Read(elkremRoot[:]) return elkremRoot }
// Usage example that expands one master key into three other cryptographically // secure keys. func Example_usage() { // Underlying hash function to use hash := sha256.New // Cryptographically secure master key. master := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this. // Non secret salt, optional (can be nil) // Recommended: hash-length sized random salt := make([]byte, hash().Size()) n, err := io.ReadFull(rand.Reader, salt) if n != len(salt) || err != nil { fmt.Println("error:", err) return } // Non secret context specific info, optional (can be nil). // Note, independent from the master key. info := []byte{0x03, 0x14, 0x15, 0x92, 0x65} // Create the key derivation function hkdf := hkdf.New(hash, master, salt, info) // Generate the required keys keys := make([][]byte, 3) for i := 0; i < len(keys); i++ { keys[i] = make([]byte, 24) n, err := io.ReadFull(hkdf, keys[i]) if n != len(keys[i]) || err != nil { fmt.Println("error:", err) return } } // Keys should contain 192 bit random keys for i := 1; i <= len(keys); i++ { fmt.Printf("Key #%d: %v\n", i, !bytes.Equal(keys[i-1], make([]byte, 24))) } // Output: // Key #1: true // Key #2: true // Key #3: true }
// deriveSymmetricKeys derives the symmetric cryptoKey and hmacKey from the // given messageKey. func deriveSymmetricKeys(messageKey *[64]byte) ( cryptoKey, hmacKey []byte, err error, ) { hkdf := hkdf.New(sha512.New, messageKey[:], nil, nil) // derive crypto key for AES-256 cryptoKey = make([]byte, 32) if _, err := io.ReadFull(hkdf, cryptoKey); err != nil { return nil, nil, err } // derive HMAC key for SHA-512 HMAC hmacKey = make([]byte, 32) if _, err := io.ReadFull(hkdf, hmacKey); err != nil { return nil, nil, err } return }
// IMPORTANT !!! // If someone changes the hash function, then the salt needs to have the exactly same lenght! // So be careful when touching this. func deriveNonce(masterKey [keySize]byte, salt [keySize]byte, context string, counterValue string) ([nonceSize]byte, error) { var data24 [nonceSize]byte // Underlying hash function to use hash := sha256.New // Create the key derivation function hkdf := hkdf.New(hash, masterKey[:], salt[:], []byte(context+counterValue)) // Generate the required keys key := make([]byte, nonceSize) n, err := io.ReadFull(hkdf, key) if n != len(key) || err != nil { return data24, err } total := copy(data24[:], key[:nonceSize]) if total != nonceSize { return data24, errors.New("Could not derive a nonce.") } return data24, nil }
// deriveRootKey derives the next root key from t1, t2, t3, and the // previousRootKeyHash (if it exists). func deriveRootKey( t1, t2, t3 *[32]byte, previousRootKeyHash *[64]byte, ) (*[32]byte, error) { master := make([]byte, 32+32+32+64) copy(master[:], t1[:]) copy(master[32:], t2[:]) copy(master[64:], t3[:]) if previousRootKeyHash != nil { copy(master[96:], previousRootKeyHash[:]) } hkdf := hkdf.New(sha512.New, master, nil, nil) // derive root key var rootKey [32]byte // we operate on 256-bit security margins if _, err := io.ReadFull(hkdf, rootKey[:]); err != nil { return nil, err } return &rootKey, nil }
func generateToken(secret []byte, payload TokenPayload) (string, error) { secretHkdf := hkdf.New(sha256.New, []byte(secret), nil, []byte(HKDF_INFO_SIGNING)) signatureSecret := make([]byte, sha256.Size) _, err := io.ReadFull(secretHkdf, signatureSecret) if err != nil { return "", err } encodedPayload, err := json.Marshal(payload) if err != nil { return "", err } // Calculate and encode the token secret mac := hmac.New(sha256.New, signatureSecret) mac.Write(encodedPayload) payloadSignature := mac.Sum(nil) tokenSecret := append(encodedPayload, payloadSignature...) return base64.URLEncoding.EncodeToString(tokenSecret), nil }
func (kx *KeyExchange) derivePassword() error { serialised, err := proto.Marshal(kx.sharedSecret.toProto()) if err != nil { return err } if kx.Testing || kx.sharedSecret.isStrongRandom() { h := hkdf.New(sha256.New, serialised, nil, []byte("PANDA strong secret expansion")) if _, err := h.Read(kx.key[:]); err != nil { return err } if _, err := h.Read(kx.meeting1[:]); err != nil { return err } if _, err := h.Read(kx.meeting2[:]); err != nil { return err } } else { var data []byte if runtime.GOARCH == "386" && runtime.GOOS == "linux" { // We're having GC problems on 32-bit systems with the // scrypt allocation. In order to help the GC out, the // scrypt computation is done in a subprocess. cmd := exec.Command("/proc/self/exe", "--panda-scrypt") var in, out bytes.Buffer binary.Write(&in, binary.LittleEndian, uint32(len(serialised))) in.Write(serialised) cmd.Stdin = &in cmd.Stdout = &out cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return err } data = out.Bytes() if len(data) != 32*3 { return errors.New("scrypt subprocess returned wrong number of bytes: " + strconv.Itoa(len(data))) } } else { if data, err = scrypt.Key(serialised, nil, 1<<17, 16, 4, 32*3); err != nil { return err } } copy(kx.key[:], data) copy(kx.meeting1[:], data[32:]) copy(kx.meeting2[:], data[64:]) } var encryptedDHPublic [32]byte rijndael.NewCipher(&kx.key).Encrypt(&encryptedDHPublic, &kx.dhPublic) l := len(encryptedDHPublic) if padding := kx.meetingPlace.Padding(); l > padding { return errors.New("panda: initial message too large for meeting place") } else if l < padding { l = padding } kx.message1 = make([]byte, l) copy(kx.message1, encryptedDHPublic[:]) if _, err := io.ReadFull(kx.rand, kx.message1[len(encryptedDHPublic):]); err != nil { return err } return nil }
func TestSessions(t *testing.T) { tmpdir, keyDB, err := createDB() if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) defer keyDB.Close() // make sure sessions are empty initially sessionKey := base64.Encode(cipher.SHA512([]byte("key"))) rootKeyHash, _, _, err := keyDB.GetSession(sessionKey) if err != sql.ErrNoRows { t.Error("should fail with sql.ErrNoRows") } if rootKeyHash != "" { t.Error("rootKeyHash is supposed to be empty") } // store root key hash rk := base64.Encode(cipher.SHA256([]byte("rootkey"))) master := make([]byte, 96) if _, err := io.ReadFull(cipher.RandReader, master); err != nil { t.Fatal(err) } kdf := hkdf.New(sha512.New, master, nil, nil) chainKey := make([]byte, 32) if _, err := io.ReadFull(kdf, chainKey); err != nil { t.Fatal(err) } send, recv, err := deriveKeys(chainKey, kdf) if err != nil { t.Fatal(err) } err = keyDB.AddSession(sessionKey, rk, base64.Encode(chainKey), send, recv) if err != nil { t.Fatal(err) } // check root key hash rootKeyHash, _, n, err := keyDB.GetSession(sessionKey) if err != nil { t.Fatal(err) } if rootKeyHash != rk { t.Error("rootKeyHash is supposed to equal rk") } if n != msg.NumOfFutureKeys { t.Error("n is supposed to equal msg.NumOfFutureKeys") } // update root key hash chainKey = make([]byte, 32) if _, err := io.ReadFull(kdf, chainKey); err != nil { t.Fatal(err) } send, recv, err = deriveKeys(chainKey, kdf) if err != nil { t.Fatal(err) } err = keyDB.AddSession(sessionKey, rk, base64.Encode(chainKey), send, recv) if err != nil { t.Fatal(err) } // check updated root key hash rootKeyHash, _, n, err = keyDB.GetSession(sessionKey) if err != nil { t.Fatal(err) } if rootKeyHash != rk { t.Error("rootKeyHash is supposed to equal rk") } if n != 2*msg.NumOfFutureKeys { t.Error("n is supposed to equal 2*msg.NumOfFutureKeys") } // TODO: improve tests for message keys _, err = keyDB.GetMessageKey(sessionKey, true, 0) if err != nil { t.Fatal(err) } if err := keyDB.DelMessageKey(sessionKey, true, 0); err != nil { t.Fatal(err) } }
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 }