func deriveKeys(chainKey []byte, kdf io.Reader) (send, recv []string, err error) { buffer := make([]byte, 64) for i := 0; i < msg.NumOfFutureKeys; i++ { if _, err := io.ReadFull(kdf, buffer); err != nil { return nil, nil, err } send = append(send, base64.Encode(cipher.HMAC(chainKey, buffer))) if _, err := io.ReadFull(kdf, buffer); err != nil { return nil, nil, err } recv = append(recv, base64.Encode(cipher.HMAC(chainKey, buffer))) } return }
// generateMessageKeys generates the next numOfKeys many session keys from // from rootKey for given senderIdentity and recipientIdentity. // If recipientKeys is true the generated sender and reciever keys are stored in // reverse order. // It uses senderSessionPub and recipientPub in the process and calls // keyStore.StoresSession and keyStore.SetSessionState to store the result. func generateMessageKeys( senderIdentity, recipientIdentity string, senderIdentityPubkeyHash, recipientIdentityPubkeyHash string, rootKey *[32]byte, recipientKeys bool, senderSessionPub, recipientPub *[32]byte, numOfKeys uint64, keyStore session.Store, ) error { var ( identities string send []string recv []string ) // identity_fix = HASH(SORT(SenderNym, RecipientNym)) if senderIdentity < recipientIdentity { identities = senderIdentity + recipientIdentity } else { identities = recipientIdentity + senderIdentity } identityFix := cipher.SHA512([]byte(identities)) recipientPubHash := cipher.SHA512(recipientPub[:]) senderSessionPubHash := cipher.SHA512(senderSessionPub[:]) chainKey := rootKey[:] for i := uint64(0); i < numOfKeys; i++ { // messagekey_send[i] = HMAC_HASH(chainkey, "MESSAGE" | HASH(RecipientPub) | identity_fix) buffer := append([]byte("MESSAGE"), recipientPubHash...) buffer = append(buffer, identityFix...) send = append(send, base64.Encode(cipher.HMAC(chainKey, buffer))) // messagekey_recv[i] = HMAC_HASH(chainkey, "MESSAGE" | HASH(SenderSessionPub) | identity_fix) buffer = append([]byte("MESSAGE"), senderSessionPubHash...) buffer = append(buffer, identityFix...) recv = append(recv, base64.Encode(cipher.HMAC(chainKey, buffer))) // chainkey = HMAC_HASH(chainkey, "CHAIN" ) chainKey = cipher.HMAC(chainKey, []byte("CHAIN"))[:32] } // calculate root key hash rootKeyHash := base64.Encode(cipher.SHA512(rootKey[:])) bzero.Bytes(rootKey[:]) // reverse key material, if necessary if recipientKeys { send, recv = recv, send } // store session var sessionKey string if recipientKeys { key := recipientIdentityPubkeyHash key += senderIdentityPubkeyHash key += base64.Encode(cipher.SHA512(recipientPub[:])) key += base64.Encode(cipher.SHA512(senderSessionPub[:])) sessionKey = base64.Encode(cipher.SHA512([]byte(key))) } else { key := senderIdentityPubkeyHash key += recipientIdentityPubkeyHash key += base64.Encode(cipher.SHA512(senderSessionPub[:])) key += base64.Encode(cipher.SHA512(recipientPub[:])) sessionKey = base64.Encode(cipher.SHA512([]byte(key))) } err := keyStore.StoreSession(sessionKey, rootKeyHash, base64.Encode(chainKey), send, recv) if err != nil { return err } return nil }