// ECDH computes a Diffie-Hellman (DH) key exchange over the elliptic curve (EC) // curve25519. If ownPublicKey is given it is used to check for the key // reflection attack. Otherwise it is derived from privateKey. func ECDH(privateKey, peersPublicKey, ownPublicKey *[32]byte) (*[32]byte, error) { var ( sharedKey [32]byte pubKey []byte ) // check mandatory key length if privateKey == nil { return nil, log.Error("cipher: curve25519.ECDH(): privateKey == nil") } if peersPublicKey == nil { return nil, log.Error("cipher: curve25519.ECDH(): peersPublicKey == nil") } // check for key reflection attack if ownPublicKey != nil { pubKey = ownPublicKey[:] } else { var publicKey [32]byte curve25519.ScalarBaseMult(&publicKey, privateKey) pubKey = publicKey[:] } if bytes.Equal(pubKey, peersPublicKey[:]) { return nil, log.Errorf("cipher: curve25519.ECDH(): publicKey == peersPublicKey") } // perform Diffie-Hellman key exchange curve25519.ScalarMult(&sharedKey, privateKey, peersPublicKey) return &sharedKey, nil }
// Verify an answer. secret is the own secret key, testKey is the public key to test ownership on func Verify(answer *[AnswerSize]byte, secret *[PrivateKeySize]byte, testKey *[PublicKeySize]byte) bool { var sharedSecret [PublicKeySize]byte var timeb [8]byte var inChallenge [ChallengeSize]byte var hashIn [AnswerSize]byte var inHash [PrivateKeySize]byte t1, t2 := false, false copy(inChallenge[:], answer[:ChallengeSize]) // Copy full challenge copy(timeb[:], inChallenge[:8]) // First 8 byte of challenge are time copy(inHash[:], answer[ChallengeSize:]) // Copy hash tempPriv, _, outChallenge := genTempKey(timeb, secret) if *outChallenge == inChallenge { t1 = true } curve25519.ScalarMult(&sharedSecret, tempPriv, testKey) copy(hashIn[0:ChallengeSize], outChallenge[:]) copy(hashIn[ChallengeSize:], sharedSecret[:]) outHash := sha256.Sum256(hashIn[:]) if inHash == outHash { t2 = true } if t1 && t2 { return true } return false }
func (r *Ratchet) EncryptFirst(out, msg []byte, theirRatchetPublic *[32]byte) []byte { r.saved = make(map[[32]byte]map[uint32]savedKey) r.ratchet = true r.randBytes(r.ourRatchetPrivate[:]) copy(r.theirRatchetPublic[:], theirRatchetPublic[:]) copy(r.theirAuthPublic[:], theirRatchetPublic[:]) var sharedKey [32]byte curve25519.ScalarMult(&sharedKey, &r.ourRatchetPrivate, &r.theirRatchetPublic) h := hmac.New(sha256.New, sharedKey[:]) deriveKey(&r.rootKey, rootKeyLabel, h) deriveKey(&r.recvHeaderKey, headerKeyLabel, h) deriveKey(&r.nextSendHeaderKey, sendHeaderKeyLabel, h) deriveKey(&r.nextRecvHeaderKey, nextRecvHeaderKeyLabel, h) deriveKey(&r.recvChainKey, chainKeyLabel, h) var ourRatchetPublic [32]byte curve25519.ScalarBaseMult(&ourRatchetPublic, &r.ourRatchetPrivate) tag_idx := len(out) out = append(out, make([]byte, authSize)...) out = append(out, ourRatchetPublic[:]...) out = r.encrypt(out, msg) r.FillAuth(out[tag_idx:][:authSize], out[tag_idx+authSize:], theirRatchetPublic) return out }
func (kx *KeyExchange) exchange1() error { reply, err := kx.meetingPlace.Exchange(kx.Log, kx.meeting1[:], kx.message1[:], kx.ShutdownChan) if err != nil { return err } var peerDHPublic, encryptedPeerDHPublic [32]byte if len(reply) < len(encryptedPeerDHPublic) { return errors.New("panda: meeting point reply too small") } copy(encryptedPeerDHPublic[:], reply) rijndael.NewCipher(&kx.key).Decrypt(&peerDHPublic, &encryptedPeerDHPublic) curve25519.ScalarMult(&kx.sharedKey, &kx.dhPrivate, &peerDHPublic) paddedLen := kx.meetingPlace.Padding() padded := make([]byte, paddedLen-24 /* nonce */ -secretbox.Overhead) binary.LittleEndian.PutUint32(padded, uint32(len(kx.kxBytes))) copy(padded[4:], kx.kxBytes) if _, err := io.ReadFull(kx.rand, padded[4+len(kx.kxBytes):]); err != nil { return err } var nonce [24]byte if _, err := io.ReadFull(kx.rand, nonce[:]); err != nil { return err } kx.message2 = make([]byte, paddedLen) copy(kx.message2, nonce[:]) secretbox.Seal(kx.message2[24:24], padded, &nonce, &kx.sharedKey) return nil }
// GetMixData decrypts the private portion of a nymaddress. func (ad *Address) GetMixData(keysLookup KeyFunc) (*AddressPrivate, error) { pubkey := new([KeySize]byte) copy(pubkey[:], ad.MixPubKey) privkey := keysLookup(pubkey) if privkey == nil { return nil, ErrNoKey } sharedSecret := new([KeySize]byte) addrKey := new([KeySize]byte) copy(addrKey[:], ad.AddressKey) curve25519.ScalarMult(sharedSecret, privkey, addrKey) cr, err := lioness.New(sharedSecret[:]) // saves some bytes and is safe against tagging if err != nil { return nil, err } privmarshal, err := cr.Decrypt(ad.PrivateData) if err != nil { return nil, err } ap := new(AddressPrivate) _, err = asn1.Unmarshal(privmarshal, ap) if err != nil { return nil, err } return ap, nil }
func (c *Conn) handshakeClient(handshakeHash hash.Hash, ephemeralPrivate *[32]byte) error { var ephemeralIdentityShared [32]byte curve25519.ScalarMult(&ephemeralIdentityShared, ephemeralPrivate, &c.Peer) digest := handshakeHash.Sum(nil) h := hmac.New(sha256.New, ephemeralIdentityShared[:]) h.Write(serverProofMagic) h.Write(digest) digest = h.Sum(digest[:0]) digestReceived := make([]byte, len(digest)+secretbox.Overhead) n, err := c.read(digestReceived) if err != nil { return err } if n != len(digest) { return shortMessageError } digestReceived = digestReceived[:n] if subtle.ConstantTimeCompare(digest, digestReceived) != 1 { return errors.New("transport: server identity incorrect") } var identityShared [32]byte curve25519.ScalarMult(&identityShared, &c.identity, &c.Peer) handshakeHash.Write(digest) digest = handshakeHash.Sum(digest[:0]) h = hmac.New(sha256.New, identityShared[:]) h.Write(clientProofMagic) h.Write(digest) finalMessage := make([]byte, 32+sha256.Size) copy(finalMessage, c.identityPublic[:]) h.Sum(finalMessage[32:32]) if _, err := c.write(finalMessage); err != nil { return err } return nil }
func (e *curve25519ECDH) GenerateSharedSecret(privKey crypto.PrivateKey, pubKey crypto.PublicKey) ([]byte, error) { var priv, pub, secret *[32]byte priv = privKey.(*[32]byte) pub = pubKey.(*[32]byte) secret = new([32]byte) curve25519.ScalarMult(secret, priv, pub) return secret[:], nil }
// ComputeSharedKey computes and returns the shared key based on the local private key and the remote public key. func (this *c255) ComputeSharedKey(remotePublicKey []byte) (error, []byte) { var remote [32]byte if len(remotePublicKey) != 32 { return errors.New("ECDH : invalid Curve25519 KeyExchange"), nil } sharedKey := new([32]byte) copy(remote[:], remotePublicKey) curve25519.ScalarMult(sharedKey, &this.privateKey, &remote) return nil, sharedKey[:] }
func (c *Conn) handshakeServer(handshakeHash hash.Hash, theirEphemeralPublic *[32]byte) error { var ephemeralIdentityShared [32]byte curve25519.ScalarMult(&ephemeralIdentityShared, &c.identity, theirEphemeralPublic) digest := handshakeHash.Sum(nil) h := hmac.New(sha256.New, ephemeralIdentityShared[:]) h.Write(serverProofMagic) h.Write(digest) digest = h.Sum(digest[:0]) if _, err := c.write(digest); err != nil { return err } handshakeHash.Write(digest) digest = handshakeHash.Sum(digest[:0]) finalMessage := make([]byte, 32+sha256.Size+secretbox.Overhead) n, err := c.read(finalMessage) if err != nil { return err } if n != 32+sha256.Size { return shortMessageError } finalMessage = finalMessage[:n] copy(c.Peer[:], finalMessage[:32]) var identityShared [32]byte curve25519.ScalarMult(&identityShared, &c.identity, &c.Peer) h = hmac.New(sha256.New, identityShared[:]) h.Write(clientProofMagic) h.Write(digest) digest = h.Sum(digest[:0]) if subtle.ConstantTimeCompare(digest, finalMessage[32:]) != 1 { return errors.New("transport: bad proof from client") } return nil }
// ClientHandshake does the client side of a ntor handshake and returnes // status, KEY_SEED, and AUTH. If status is not true or AUTH does not match // the value recieved from the server, the handshake MUST be aborted. func ClientHandshake(clientKeypair *Keypair, serverPublic *PublicKey, idPublic *PublicKey, id *NodeID) (ok bool, keySeed *KeySeed, auth *Auth) { var notOk int var secretInput bytes.Buffer // Client side uses EXP(Y,x) | EXP(B,x) var exp [SharedSecretLength]byte curve25519.ScalarMult(&exp, clientKeypair.private.Bytes(), serverPublic.Bytes()) notOk |= constantTimeIsZero(exp[:]) secretInput.Write(exp[:]) curve25519.ScalarMult(&exp, clientKeypair.private.Bytes(), idPublic.Bytes()) notOk |= constantTimeIsZero(exp[:]) secretInput.Write(exp[:]) keySeed, auth = ntorCommon(secretInput, id, idPublic, clientKeypair.public, serverPublic) return notOk == 0, keySeed, auth }
func FillAuthWith(ourAuthPrivate *[32]byte) func([]byte, []byte, *[32]byte) { return func(tag, data []byte, theirAuthPublic *[32]byte) { var sharedAuthKey [32]byte curve25519.ScalarMult(&sharedAuthKey, ourAuthPrivate, theirAuthPublic) var ourAuthPublic [32]byte curve25519.ScalarBaseMult(&ourAuthPublic, ourAuthPrivate) h := hmac.New(sha256.New, sharedAuthKey[:]) h.Write(data) copy(tag, h.Sum(nil)) } }
// Answer an authentication challenge. Secret is the private key belonging to the public key to be tested func Answer(challenge *[ChallengeSize]byte, secret *[PrivateKeySize]byte) *[AnswerSize]byte { // return challenge|hash(challenge,DH(Secret,challenge.Pub)) var sharedSecret [PublicKeySize]byte var tempPub [PublicKeySize]byte var hashIn, answer [AnswerSize]byte copy(hashIn[0:ChallengeSize], challenge[:]) copy(tempPub[:], challenge[8:]) curve25519.ScalarMult(&sharedSecret, secret, &tempPub) copy(hashIn[ChallengeSize:], sharedSecret[:]) mHash := sha256.Sum256(hashIn[:]) copy(answer[:ChallengeSize], challenge[:]) copy(answer[ChallengeSize:], mHash[:]) return &answer }
// Encrypt acts like append() but appends an encrypted version of msg to out. func (r *Ratchet) Encrypt(out, msg []byte) []byte { if r.ratchet { r.randBytes(r.sendRatchetPrivate[:]) copy(r.sendHeaderKey[:], r.nextSendHeaderKey[:]) var sharedKey, keyMaterial [32]byte curve25519.ScalarMult(&sharedKey, &r.sendRatchetPrivate, &r.recvRatchetPublic) sha := sha256.New() sha.Write(rootKeyUpdateLabel) sha.Write(r.rootKey[:]) sha.Write(sharedKey[:]) if r.v2 { sha.Sum(keyMaterial[:0]) h := hmac.New(sha256.New, keyMaterial[:]) deriveKey(&r.rootKey, rootKeyLabel, h) deriveKey(&r.nextSendHeaderKey, sendHeaderKeyLabel, h) deriveKey(&r.sendChainKey, chainKeyLabel, h) } else { sha.Sum(r.rootKey[:0]) h := hmac.New(sha256.New, r.rootKey[:]) deriveKey(&r.nextSendHeaderKey, sendHeaderKeyLabel, h) deriveKey(&r.sendChainKey, chainKeyLabel, h) } r.prevSendCount, r.sendCount = r.sendCount, 0 r.ratchet = false } h := hmac.New(sha256.New, r.sendChainKey[:]) var messageKey [32]byte deriveKey(&messageKey, messageKeyLabel, h) deriveKey(&r.sendChainKey, chainKeyStepLabel, h) var sendRatchetPublic [32]byte curve25519.ScalarBaseMult(&sendRatchetPublic, &r.sendRatchetPrivate) var header [headerSize]byte var headerNonce, messageNonce [24]byte r.randBytes(headerNonce[:]) r.randBytes(messageNonce[:]) binary.LittleEndian.PutUint32(header[0:4], r.sendCount) binary.LittleEndian.PutUint32(header[4:8], r.prevSendCount) copy(header[8:], sendRatchetPublic[:]) copy(header[nonceInHeaderOffset:], messageNonce[:]) out = append(out, headerNonce[:]...) out = secretbox.Seal(out, header[:], &headerNonce, &r.sendHeaderKey) r.sendCount++ return secretbox.Seal(out, msg, &messageNonce, &messageKey) }
func computeSharedSecretWithPasswordHash(privateKey *[32]byte, herPublicKey *[32]byte, passwordHash *[32]byte) [32]byte { // TODO: check this, is this right way to check for empty [32]byte? var computedKey [32]byte curve25519.ScalarMult(&computedKey, privateKey, herPublicKey) buff := make([]byte, 64) copy(buff[:32], computedKey[:]) copy(buff[32:64], passwordHash[:]) secret := sha256.Sum256(buff) return secret }
func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { var kp curve25519KeyPair if err := kp.generate(rand); err != nil { return nil, err } if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { return nil, err } packet, err := c.readPacket() if err != nil { return nil, err } var reply kexECDHReplyMsg if err = Unmarshal(packet, &reply); err != nil { return nil, err } if len(reply.EphemeralPubKey) != 32 { return nil, errors.New("ssh: peer's curve25519 public value has wrong length") } var servPub, secret [32]byte copy(servPub[:], reply.EphemeralPubKey) curve25519.ScalarMult(&secret, &kp.priv, &servPub) if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { return nil, errors.New("ssh: peer's curve25519 public value has wrong order") } h := crypto.SHA256.New() magics.write(h) writeString(h, reply.HostKey) writeString(h, kp.pub[:]) writeString(h, reply.EphemeralPubKey) kInt := new(big.Int).SetBytes(secret[:]) K := make([]byte, intLength(kInt)) marshalInt(K, kInt) h.Write(K) return &kexResult{ H: h.Sum(nil), K: K, HostKey: reply.HostKey, Signature: reply.Signature, Hash: crypto.SHA256, }, nil }
func (c ecdh25519) ComputeSecret(private PrivateKey, peersPublic PublicKey) (secret []byte) { if len(private) != 32 { panic("ecdh: private key is not 32 byte") } if len(peersPublic) != 32 { panic("ecdh: peers public key is not 32 byte") } var sec, pri, pub [32]byte copy(pri[:], private) copy(pub[:], peersPublic) curve25519.ScalarMult(&sec, &pri, &pub) secret = sec[:] return }
// CalculateSharedSecret calculates a shared secret from the given parameters. If myPrivateKey is nil, it will // return only nils. If Nonce is nil, a nonce will be created func CalculateSharedSecret(peerPublicKey, myPrivateKey, nonceIn *[KeySize]byte) (secret, nonceOut *[KeySize]byte) { var err error if myPrivateKey == nil || peerPublicKey == nil { return nil, nil } if nonceIn == nil { nonceOut, err = genNonce() if err != nil { return nil, nil } } else { nonceOut = nonceIn } secretOne := new([KeySize]byte) curve25519.ScalarMult(secretOne, myPrivateKey, peerPublicKey) return ExpandSecret(nonceOut[:], secretOne[:]), nonceOut }
func (r *Ratchet) DecryptFirst(ciphertext []byte, ourRatchetPrivate *[32]byte) ([]byte, error) { r.saved = make(map[[32]byte]map[uint32]savedKey) if len(ciphertext) < OverheadFirst { return nil, errors.New("first message too short") } copy(r.ourRatchetPrivate[:], ourRatchetPrivate[:]) copy(r.ourAuthPrivate[:], ourRatchetPrivate[:]) tag := ciphertext[:authSize] var sharedKey [32]byte copy(r.theirRatchetPublic[:], ciphertext[authSize:][:handshakePreHeaderSize]) curve25519.ScalarMult(&sharedKey, &r.ourRatchetPrivate, &r.theirRatchetPublic) h := hmac.New(sha256.New, sharedKey[:]) deriveKey(&r.rootKey, rootKeyLabel, h) deriveKey(&r.sendHeaderKey, headerKeyLabel, h) deriveKey(&r.nextRecvHeaderKey, sendHeaderKeyLabel, h) deriveKey(&r.nextSendHeaderKey, nextRecvHeaderKeyLabel, h) deriveKey(&r.sendChainKey, chainKeyLabel, h) return r.decryptAndCheckAuth(tag, ciphertext[authSize:], ciphertext[authSize+handshakePreHeaderSize:]) }
// GetPrivate gets the shared secret from a header. func (tmp AddressTemplate) GetPrivate(header, MailboxAddress []byte) (nym, secret []byte, err error) { rh := new(RelayHeader) _, err = asn1.Unmarshal(header, rh) if err != nil { return nil, nil, err } symkey := tmp.genSymKey(rh.Nonce, rh.ReceiverPubKey, MailboxAddress) HMACHead := calcHmac(symkey, rh.Nonce, rh.ReceiverPubKey, rh.EncNym) if !hmac.Equal(rh.HMACHead, HMACHead) { return nil, nil, ErrHMAC } nym = decryptNym(symkey, rh.EncNym) recPub, recPriv := tmp.genDetermKeys(rh.Nonce, nym) if !bytes.Equal(recPub[:], rh.ReceiverPubKey) { return nil, nil, ErrBadKey } sharedSecret := new([KeySize]byte) senderPubKey := new([KeySize]byte) copy(senderPubKey[:], rh.SenderKey) curve25519.ScalarMult(sharedSecret, recPriv, senderPubKey) return nym, sharedSecret[:], nil }
// GetHeader returns the header for a relay message and a secret for encryption. func (ap AddressPrivate) GetHeader() (header, secret []byte, err error) { pubkey, privkey, err := genKeyRandom() if err != nil { return nil, nil, err } rh := RelayHeader{ SenderKey: pubkey[:], Nonce: ap.Nonce, ReceiverPubKey: ap.ReceiverPubKey, EncNym: ap.EncNym, HMACHead: ap.HMACHead, } d, err := asn1.Marshal(rh) if err != nil { return nil, nil, err } sharedSecret := new([KeySize]byte) receiverPubKey := new([KeySize]byte) copy(receiverPubKey[:], ap.ReceiverPubKey) curve25519.ScalarMult(sharedSecret, privkey, receiverPubKey) return d, sharedSecret[:], nil }
func CheckAuthWith(prt ProfileRatchet) func([]byte, []byte, []byte, *[32]byte) error { return func(tag, data, msg []byte, ourAuthPrivate *[32]byte) error { var sharedAuthKey [32]byte message := new(proto.Message) unpadMsg := proto.Unpad(msg) err := message.Unmarshal(unpadMsg) if err != nil { return err } profile, err := prt(message.Dename, message.DenameLookup) if err != nil { return err } chatProfileBytes, err := client.GetProfileField(profile, PROFILE_FIELD_ID) if err != nil { return err } chatProfile := new(proto.Profile) if err := chatProfile.Unmarshal(chatProfileBytes); err != nil { return err } theirAuthPublic := (*[32]byte)(&chatProfile.MessageAuthKey) curve25519.ScalarMult(&sharedAuthKey, ourAuthPrivate, theirAuthPublic) h := hmac.New(sha256.New, sharedAuthKey[:]) h.Write(data) if subtle.ConstantTimeCompare(tag, h.Sum(nil)[:len(tag)]) == 0 { return errors.New("Authentication failed: failed to reproduce envelope auth tag using the current auth pubkey from dename") } return nil } }
func (c *Conn) Handshake() error { var ephemeralPrivate, ephemeralPublic, ephemeralShared [32]byte if _, err := io.ReadFull(rand.Reader, ephemeralPrivate[:]); err != nil { return err } curve25519.ScalarBaseMult(&ephemeralPublic, &ephemeralPrivate) if _, err := c.write(ephemeralPublic[:]); err != nil { return err } var theirEphemeralPublic [32]byte if n, err := c.read(theirEphemeralPublic[:]); err != nil || n != len(theirEphemeralPublic) { if err == nil { err = shortMessageError } return err } handshakeHash := sha256.New() if c.isServer { handshakeHash.Write(theirEphemeralPublic[:]) handshakeHash.Write(ephemeralPublic[:]) } else { handshakeHash.Write(ephemeralPublic[:]) handshakeHash.Write(theirEphemeralPublic[:]) } curve25519.ScalarMult(&ephemeralShared, &ephemeralPrivate, &theirEphemeralPublic) c.setupKeys(&ephemeralShared) if c.isServer { return c.handshakeServer(handshakeHash, &theirEphemeralPublic) } return c.handshakeClient(handshakeHash, &ephemeralPrivate) }
func dhKeyGen(priv, pub *[32]byte) *[32]byte { key := new([32]byte) curve25519.ScalarMult(key, priv, pub) hashed := blake2b.Sum256(key[:]) return &hashed }
// CompleteKeyExchange takes a KeyExchange message from the other party and // establishes the ratchet. func (r *Ratchet) CompleteKeyExchange(kx *pond.KeyExchange, isV2 bool) error { if r.kxPrivate0 == nil { return errors.New("ratchet: handshake already complete") } var public0 [32]byte curve25519.ScalarBaseMult(&public0, r.kxPrivate0) if len(kx.Dh) != len(public0) { return errors.New("ratchet: peer's key exchange is invalid") } if len(kx.Dh1) != len(public0) { return errors.New("ratchet: peer using old-form key exchange") } var amAlice bool switch bytes.Compare(public0[:], kx.Dh) { case -1: amAlice = true case 1: amAlice = false case 0: return errors.New("ratchet: peer echoed our own DH values back") } var theirDH [32]byte copy(theirDH[:], kx.Dh) keyMaterial := make([]byte, 0, 32*5) var sharedKey [32]byte curve25519.ScalarMult(&sharedKey, r.kxPrivate0, &theirDH) keyMaterial = append(keyMaterial, sharedKey[:]...) if amAlice { curve25519.ScalarMult(&sharedKey, r.MyIdentityPrivate, &theirDH) keyMaterial = append(keyMaterial, sharedKey[:]...) curve25519.ScalarMult(&sharedKey, r.kxPrivate0, r.TheirIdentityPublic) keyMaterial = append(keyMaterial, sharedKey[:]...) if !isV2 { keyMaterial = append(keyMaterial, r.MySigningPublic[:]...) keyMaterial = append(keyMaterial, r.TheirSigningPublic[:]...) } } else { curve25519.ScalarMult(&sharedKey, r.kxPrivate0, r.TheirIdentityPublic) keyMaterial = append(keyMaterial, sharedKey[:]...) curve25519.ScalarMult(&sharedKey, r.MyIdentityPrivate, &theirDH) keyMaterial = append(keyMaterial, sharedKey[:]...) if !isV2 { keyMaterial = append(keyMaterial, r.TheirSigningPublic[:]...) keyMaterial = append(keyMaterial, r.MySigningPublic[:]...) } } h := hmac.New(sha256.New, keyMaterial) deriveKey(&r.rootKey, rootKeyLabel, h) if amAlice { deriveKey(&r.recvHeaderKey, headerKeyLabel, h) deriveKey(&r.nextSendHeaderKey, sendHeaderKeyLabel, h) deriveKey(&r.nextRecvHeaderKey, nextRecvHeaderKeyLabel, h) deriveKey(&r.recvChainKey, chainKeyLabel, h) copy(r.recvRatchetPublic[:], kx.Dh1) } else { deriveKey(&r.sendHeaderKey, headerKeyLabel, h) deriveKey(&r.nextRecvHeaderKey, sendHeaderKeyLabel, h) deriveKey(&r.nextSendHeaderKey, nextRecvHeaderKeyLabel, h) deriveKey(&r.sendChainKey, chainKeyLabel, h) copy(r.sendRatchetPrivate[:], r.kxPrivate1[:]) } r.ratchet = amAlice r.kxPrivate0 = nil r.kxPrivate1 = nil r.v2 = isV2 return nil }
// SharedSecret returns a Curve25519 shared secret derived from privateKey and otherPublicKey. func SharedSecret(privateKey, otherPublicKey [keySize]byte) [keySize]byte { var k [keySize]byte curve25519.ScalarMult(&k, &privateKey, &otherPublicKey) return k }
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { packet, err := c.readPacket() if err != nil { return } var kexInit kexECDHInitMsg if err = Unmarshal(packet, &kexInit); err != nil { return } if len(kexInit.ClientPubKey) != 32 { return nil, errors.New("ssh: peer's curve25519 public value has wrong length") } var kp curve25519KeyPair if err := kp.generate(rand); err != nil { return nil, err } var clientPub, secret [32]byte copy(clientPub[:], kexInit.ClientPubKey) curve25519.ScalarMult(&secret, &kp.priv, &clientPub) if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { return nil, errors.New("ssh: peer's curve25519 public value has wrong order") } hostKeyBytes := priv.PublicKey().Marshal() h := crypto.SHA256.New() magics.write(h) writeString(h, hostKeyBytes) writeString(h, kexInit.ClientPubKey) writeString(h, kp.pub[:]) kInt := new(big.Int).SetBytes(secret[:]) K := make([]byte, intLength(kInt)) marshalInt(K, kInt) h.Write(K) H := h.Sum(nil) sig, err := signAndMarshal(priv, rand, H) if err != nil { return nil, err } reply := kexECDHReplyMsg{ EphemeralPubKey: kp.pub[:], HostKey: hostKeyBytes, Signature: sig, } if err := c.writePacket(Marshal(&reply)); err != nil { return nil, err } return &kexResult{ H: H, K: K, HostKey: hostKeyBytes, Signature: sig, Hash: crypto.SHA256, }, nil }
func (r *Ratchet) Decrypt(ciphertext []byte) ([]byte, error) { msg, err := r.trySavedKeys(ciphertext) if err != nil || msg != nil { return msg, err } sealedHeader := ciphertext[:sealedHeaderSize] sealedMessage := ciphertext[sealedHeaderSize:] var nonce [24]byte copy(nonce[:], sealedHeader) sealedHeader = sealedHeader[len(nonce):] header, ok := secretbox.Open(nil, sealedHeader, &nonce, &r.recvHeaderKey) ok = ok && !isZeroKey(&r.recvHeaderKey) if ok { if len(header) != headerSize { return nil, errors.New("ratchet: incorrect header size") } messageNum := binary.LittleEndian.Uint32(header[:4]) provisionalChainKey, messageKey, savedKeys, err := r.saveKeys(&r.recvHeaderKey, &r.recvChainKey, messageNum, r.recvCount) if err != nil { return nil, err } copy(nonce[:], header[nonceInHeaderOffset:]) msg, ok := secretbox.Open(nil, sealedMessage, &nonce, &messageKey) if !ok { return nil, errors.New("ratchet: corrupt message") } copy(r.recvChainKey[:], provisionalChainKey[:]) r.mergeSavedKeys(savedKeys) r.recvCount = messageNum + 1 return msg, nil } header, ok = secretbox.Open(nil, sealedHeader, &nonce, &r.nextRecvHeaderKey) if !ok { return nil, errors.New("ratchet: cannot decrypt") } if len(header) != headerSize { return nil, errors.New("ratchet: incorrect header size") } if r.ratchet { return nil, errors.New("ratchet: received message encrypted to next header key without ratchet flag set") } messageNum := binary.LittleEndian.Uint32(header[:4]) prevMessageCount := binary.LittleEndian.Uint32(header[4:8]) _, _, oldSavedKeys, err := r.saveKeys(&r.recvHeaderKey, &r.recvChainKey, prevMessageCount, r.recvCount) if err != nil { return nil, err } var dhPublic, sharedKey, rootKey, chainKey, keyMaterial [32]byte copy(dhPublic[:], header[8:]) curve25519.ScalarMult(&sharedKey, &r.sendRatchetPrivate, &dhPublic) sha := sha256.New() sha.Write(rootKeyUpdateLabel) sha.Write(r.rootKey[:]) sha.Write(sharedKey[:]) var rootKeyHMAC hash.Hash if r.v2 { sha.Sum(keyMaterial[:0]) rootKeyHMAC = hmac.New(sha256.New, keyMaterial[:]) deriveKey(&rootKey, rootKeyLabel, rootKeyHMAC) } else { sha.Sum(rootKey[:0]) rootKeyHMAC = hmac.New(sha256.New, rootKey[:]) } deriveKey(&chainKey, chainKeyLabel, rootKeyHMAC) provisionalChainKey, messageKey, savedKeys, err := r.saveKeys(&r.nextRecvHeaderKey, &chainKey, messageNum, 0) if err != nil { return nil, err } copy(nonce[:], header[nonceInHeaderOffset:]) msg, ok = secretbox.Open(nil, sealedMessage, &nonce, &messageKey) if !ok { return nil, errors.New("ratchet: corrupt message") } copy(r.rootKey[:], rootKey[:]) copy(r.recvChainKey[:], provisionalChainKey[:]) copy(r.recvHeaderKey[:], r.nextRecvHeaderKey[:]) deriveKey(&r.nextRecvHeaderKey, sendHeaderKeyLabel, rootKeyHMAC) for i := range r.sendRatchetPrivate { r.sendRatchetPrivate[i] = 0 } copy(r.recvRatchetPublic[:], dhPublic[:]) r.recvCount = messageNum + 1 r.mergeSavedKeys(oldSavedKeys) r.mergeSavedKeys(savedKeys) r.ratchet = true return msg, nil }
func (c *OnionConnection) handleCreateNTOR(circID CircuitID, data []byte, newHandshake bool) ActionableError { if len(data) < 84 { return RefuseCircuit(errors.New("didn't get enough data"), DESTROY_REASON_PROTOCOL) } _, alreadyThere := c.circuits[circID] if alreadyThere { return CloseConnection(errors.New("nope")) } fingerprint := data[0:20] myFingerprint := c.usedTLSCtx.Fingerprint for i, v := range fingerprint { if v != myFingerprint[i] { Log(LOG_INFO, "FP mismatch %s != %s", myFingerprint, fingerprint) return RefuseCircuit(errors.New("that's not me"), DESTROY_REASON_PROTOCOL) } } var key_X [32]byte copy(key_X[:], data[52:84]) mExpand := []byte("ntor-curve25519-sha256-1:key_expand") tKey := []byte("ntor-curve25519-sha256-1:key_extract") tMac := []byte("ntor-curve25519-sha256-1:mac") tVerify := []byte("ntor-curve25519-sha256-1:verify") var key_y [32]byte CRandBytes(key_y[:]) key_y[0] &= 248 key_y[31] &= 127 key_y[31] |= 64 var key_Y [32]byte curve25519.ScalarBaseMult(&key_Y, &key_y) var buffer bytes.Buffer var tmpHolder [32]byte curve25519.ScalarMult(&tmpHolder, &key_y, &key_X) buffer.Write(tmpHolder[:]) curve25519.ScalarMult(&tmpHolder, &c.parentOR.ntorPrivate, &key_X) buffer.Write(tmpHolder[:]) buffer.Write(fingerprint) buffer.Write(c.parentOR.ntorPublic[:]) buffer.Write(key_X[:]) buffer.Write(key_Y[:]) buffer.Write([]byte("ntor-curve25519-sha256-1")) secretInput := buffer.Bytes() kdf := KDFHKDF(72, secretInput, tKey, mExpand) hhmac := hmac.New(sha256.New, tVerify) hhmac.Write(secretInput) verify := hhmac.Sum(nil) buffer.Reset() buffer.Write(verify) buffer.Write(fingerprint) buffer.Write(c.parentOR.ntorPublic[:]) buffer.Write(key_Y[:]) buffer.Write(key_X[:]) buffer.Write([]byte("ntor-curve25519-sha256-1Server")) authInput := buffer.Bytes() hhmac = hmac.New(sha256.New, tMac) hhmac.Write(authInput) auth := hhmac.Sum(nil) // XXX check for infinity cmd := CMD_CREATED2 if !newHandshake { cmd = CMD_CREATED } writeCell := NewCell(c.negotiatedVersion, circID, cmd, nil) writeCellBuf := writeCell.Data() if newHandshake { writeCellBuf[0] = 0 writeCellBuf[1] = 64 copy(writeCellBuf[2:34], key_Y[:]) copy(writeCellBuf[34:], auth) } else { copy(writeCellBuf[0:32], key_Y[:]) copy(writeCellBuf[32:], auth) } circ := NewCircuit(circID, kdf[0:20], kdf[20:40], kdf[40:56], kdf[56:72]) c.circuits[circID] = circ c.writeQueue <- writeCell.Bytes() return nil }
func scalarMult(dst, in, base *Curve25519Key) { curve25519.ScalarMult((*[Curve25519KeySize]byte)(dst), (*[Curve25519KeySize]byte)(in), (*[Curve25519KeySize]byte)(base)) }
// Precompute calculates the shared key between peersPublicKey and privateKey // and writes it to sharedKey. The shared key can be used with // OpenAfterPrecomputation and SealAfterPrecomputation to speed up processing // when using the same pair of keys repeatedly. func Precompute(sharedKey, peersPublicKey, privateKey *[32]byte) { curve25519.ScalarMult(sharedKey, privateKey, peersPublicKey) salsa.HSalsa20(sharedKey, &zeros, sharedKey, &salsa.Sigma) }