Skip to content

Commit

Permalink
Use a better ratchet system
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiocolacio committed Dec 9, 2018
1 parent d603d4b commit d19622c
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 111 deletions.
81 changes: 44 additions & 37 deletions crypto/eecdh.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import(
"golang.org/x/crypto/pbkdf2"
"errors"
"math/big"
"fmt"
)

const(
Expand All @@ -27,10 +28,9 @@ var(
)

type EncryptedMessage struct {
Ax []byte // Elliptic-Curve X-value of the message sender
Ay []byte // Elliptic-Curve Y-value of the message sender
Bx []byte // Elliptic-Curve X-value of the message receiver
By []byte // Elliptic-Curve Y-value of the message receiver
Sid int // The index of this sender's key to use in this diffie-hellman
Rid int // The index of the receiver's key to use in this diffie-hellman
Nxt []byte // Elliptic-Curve public data for the next message (encrypted)
IV []byte // AES IV used to encrypt the message and HMAC key
Msg []byte // AES encrypted message data
Key []byte // AES encrypted HMAC key
Expand All @@ -42,34 +42,45 @@ func DeriveKey(mother []byte, keysize int) []byte {
return pbkdf2.Key(mother, nil, 4096, keysize, secureHash)
}

func ECDH(priv []byte, x, y *big.Int) []byte {
// Create shared secret xp from peer's public key and our private key
xp, _ := Curve.ScalarMult(x, y, priv)

// Derive an AES key from our shared secret
return DeriveKey(xp.Bytes(), aesKeySize)
}

// Encrypt encrypts clearText using a shared secret acquired through an
// elliptic-curve diffie-hellman key exchange.
//
// Your private diffie-hellman information, priv, is used with the peer's
// public diffie-hellman information (bx, by), to create a shared AES session
// key to encrypt clearText with. Returns an EncryptedMessage and an error.
func EncryptMessage(clearText, priv []byte, ax, ay, bx, by *big.Int) (msg *EncryptedMessage, err error) {
// Create shared secret xp from peer's public key and our private key
xp, _ := Curve.ScalarMult(bx, by, priv)

// Derive an AES key from our shared secret
aesKey := DeriveKey(xp.Bytes(), aesKeySize)

func EncryptMessage(clearText, aesKey, nxt []byte, sid, rid int) (msg *EncryptedMessage, err error) {
// Create a random HMAC key
hmacKey := make([]byte, hmacKeySize)
if _, err := rand.Read(hmacKey); err != nil {
return nil, err
}

fmt.Println(nxt)

// Add PKCS7 padding to clearText
paddedClearText, err := PKCS7Pad(clearText, aes.BlockSize)
if err != nil {
return nil, err
}

// Add PKCS7 padding to next key
nxt, err = PKCS7Pad(nxt, aes.BlockSize)
if err != nil {
return nil, err
}

// Create buffers for ciphertexts
cipherText := make([]byte, len(paddedClearText))
encryptedKey := make([]byte, len(hmacKey))
encryptedNxt := make([]byte, len(nxt))

// Create AES block cipher
aesCipher, err := aes.NewCipher(aesKey)
Expand All @@ -91,17 +102,19 @@ func EncryptMessage(clearText, priv []byte, ax, ay, bx, by *big.Int) (msg *Encry
cbc = cipher.NewCBCEncrypter(aesCipher, iv)
cbc.CryptBlocks(encryptedKey, hmacKey)

// Encrypt nxt key with CBC block encrypter
cbc = cipher.NewCBCEncrypter(aesCipher, iv)
cbc.CryptBlocks(encryptedNxt, nxt)

// Generate MAC tag for data
mac := hmac.New(secureHash, hmacKey)
mac.Write(cipherText)
tag := mac.Sum(nil)

msg = &EncryptedMessage{
Ax: ax.Bytes(),
Ay: ay.Bytes(),
Bx: bx.Bytes(),
By: by.Bytes(),
Sid: sid,
Rid: rid,
Nxt: encryptedNxt,
IV: iv,
Msg: cipherText,
Tag: tag,
Expand All @@ -111,28 +124,11 @@ func EncryptMessage(clearText, priv []byte, ax, ay, bx, by *big.Int) (msg *Encry
return msg, err
}

func (message *EncryptedMessage) Decrypt(priv []byte, sender bool) ([]byte, error) {
x := new(big.Int)
y := new(big.Int)

if sender {
x.SetBytes(message.Bx)
y.SetBytes(message.By)
} else {
x.SetBytes(message.Ax)
y.SetBytes(message.Ay)
}

// Create shared secret xp from peer's public key and our private key
xp, _ := Curve.ScalarMult(x, y, priv)

// Derive an AES key from our shared secret
aesKey := DeriveKey(xp.Bytes(), aesKeySize)

func (message *EncryptedMessage) Decrypt(aesKey []byte) (clearText, nextKey []byte, err error) {
// Create AES block cipher
aesCipher, err := aes.NewCipher(aesKey)
if err != nil {
return nil, err
return
}

// Decrypt HMAC Key
Expand All @@ -141,18 +137,29 @@ func (message *EncryptedMessage) Decrypt(priv []byte, sender bool) ([]byte, erro

// Compare MAC tags
if !CheckMAC(message.Msg, message.Tag, message.Key) {
return nil, ErrUnexpectedMAC
err = ErrUnexpectedMAC
return
}

// Decrypt and unpad the payload
cbc = cipher.NewCBCDecrypter(aesCipher, message.IV)
cbc.CryptBlocks(message.Msg, message.Msg)
msg, err := PKCS7Unpad(message.Msg, aes.BlockSize)
if err != nil {
return nil, err
return
}

return msg, err
// Decrypt and unpad the next key
cbc = cipher.NewCBCDecrypter(aesCipher, message.IV)
cbc.CryptBlocks(message.Nxt, message.Nxt)
nxt, err := PKCS7Unpad(message.Nxt, aes.BlockSize)
if err != nil {
return
}

fmt.Println(nxt)

return msg, nxt, err
}

func CheckMAC(message, messageMAC, key []byte) bool {
Expand Down
89 changes: 67 additions & 22 deletions db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,96 @@ func init() {
}

func InitTables() error {
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS dh(
id INT PRIMARY KEY AUTO_INCREMENT,
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS pubkeys(
id INT,
owner VARCHAR(16),
pub BLOB,
priv BLOB
);`)
peer VARCHAR(16),
pubkey BLOB,
primary key (id, owner, peer));`)
if err != nil {
return err
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS privkeys(
id INT,
owner VARCHAR(16),
peer VARCHAR(16),
privkey BLOB,
primary key (id, owner, peer));`)

return err
}

func ResetTables() error {
_, err := db.Exec("DROP TABLE IF EXISTS dh")
_, err := db.Exec("DROP TABLE IF EXISTS pubkeys")
if err != nil {
return err
}

_, err = db.Exec("DROP TABLE IF EXISTS privkeys")
if err != nil {
return err
}

return InitTables()
}

func LookupPubKey(owner string) (pub []byte, err error) {
func LookupPubKey(owner, peer string, id int) (pub []byte, err error) {
row := db.QueryRow(
`SELECT pub
FROM dh
WHERE owner = ?
ORDER BY id DESC`,
owner)
`SELECT pubkey
FROM pubkeys
WHERE owner = ? AND peer = ? AND id = ?`,
owner, peer, id)
err = row.Scan(&pub)
return
}

func LookupPrivKey(owner string, pub []byte) (priv []byte, err error) {
func LatestPubKey(owner, peer string) (id int) {
row := db.QueryRow(
`SELECT priv
FROM dh
WHERE owner = ? AND pub = ? AND priv IS NOT NULL`,
owner, pub)
`SELECT id
FROM pubkeys
WHERE owner = ? AND peer = ?
ORDER BY id DESC`,
owner, peer)
err := row.Scan(&id)
if err != nil {
return 0
}
return id
}


func LookupPrivKey(owner, peer string, id int) (priv []byte, err error) {
row := db.QueryRow(
`SELECT privkey
FROM privkeys
WHERE owner = ? AND peer = ? AND id = ?
ORDER BY id DESC`,
owner, peer, id)
err = row.Scan(&priv)
return
}

func UploadKey(owner string, pub, priv []byte) error {
if priv != nil {
_, err := db.Exec(`INSERT INTO dh (owner, pub, priv) VALUES (?, ?, ?)`, owner, pub, priv)
return err
func LatestPrivKey(owner, peer string) (id int) {
row := db.QueryRow(
`SELECT id
FROM privkeys
WHERE owner = ? AND peer = ?
ORDER BY id DESC`,
owner, peer)
err := row.Scan(&id)
if err != nil {
return 0
}
_, err := db.Exec(`INSERT INTO dh (owner, pub) VALUES (?, ?)`, owner, pub)
return id
}

func UploadPubKey(owner, peer string, pubkey []byte, id int) error {
_, err := db.Exec(`INSERT INTO pubkeys (id, owner, peer, pubkey) VALUES (?, ?, ?, ?)`, id, owner, peer, pubkey)
return err
}

func UploadPrivKey(owner, peer string, privkey []byte, id int) error {
_, err := db.Exec(`INSERT INTO privkeys (id, owner, peer, privkey) VALUES (?, ?, ?, ?)`, id, owner, peer, privkey)
return err
}
Loading

0 comments on commit d19622c

Please sign in to comment.