mirror of
https://github.com/logos-messaging/logos-chat.git
synced 2026-05-16 09:29:30 +00:00
Remove unused submodules (#68)
* Remove uneeded vendored deps * remove naxoltl * remove proto definitions
This commit is contained in:
parent
d421690aaf
commit
ecfe9218c3
25
.gitmodules
vendored
25
.gitmodules
vendored
@ -6,11 +6,6 @@
|
|||||||
url = https://github.com/waku-org/nwaku.git
|
url = https://github.com/waku-org/nwaku.git
|
||||||
ignore = untracked
|
ignore = untracked
|
||||||
branch = master
|
branch = master
|
||||||
[submodule "vendor/nim-sds"]
|
|
||||||
path = vendor/nim-sds
|
|
||||||
url = https://github.com/jazzz/nim-sds.git
|
|
||||||
ignore = untracked
|
|
||||||
branch = master
|
|
||||||
[submodule "vendor/nim-protobuf-serialization"]
|
[submodule "vendor/nim-protobuf-serialization"]
|
||||||
path = vendor/nim-protobuf-serialization
|
path = vendor/nim-protobuf-serialization
|
||||||
url = https://github.com/status-im/nim-protobuf-serialization.git
|
url = https://github.com/status-im/nim-protobuf-serialization.git
|
||||||
@ -26,26 +21,6 @@
|
|||||||
url = https://github.com/narimiran/blake2.git
|
url = https://github.com/narimiran/blake2.git
|
||||||
ignore = untracked
|
ignore = untracked
|
||||||
branch = master
|
branch = master
|
||||||
[submodule "vendor/illwill"]
|
|
||||||
path = vendor/illwill
|
|
||||||
url = https://github.com/johnnovak/illwill.git
|
|
||||||
ignore = untracked
|
|
||||||
branch = master
|
|
||||||
[submodule "vendor/nim_chacha20_poly1305"]
|
|
||||||
path = vendor/nim_chacha20_poly1305
|
|
||||||
url = https://github.com/lantos-lgtm/nim_chacha20_poly1305.git
|
|
||||||
ignore = untracked
|
|
||||||
branch = master
|
|
||||||
[submodule "vendor/constantine"]
|
|
||||||
path = vendor/constantine
|
|
||||||
url = https://github.com/mratsim/constantine.git
|
|
||||||
ignore = untracked
|
|
||||||
branch = master
|
|
||||||
[submodule "vendor/nim-ffi"]
|
|
||||||
path = vendor/nim-ffi
|
|
||||||
url = https://github.com/logos-messaging/nim-ffi.git
|
|
||||||
ignore = untracked
|
|
||||||
branch = master
|
|
||||||
[submodule "vendor/libchat"]
|
[submodule "vendor/libchat"]
|
||||||
path = vendor/libchat
|
path = vendor/libchat
|
||||||
url = https://github.com/logos-messaging/libchat.git
|
url = https://github.com/logos-messaging/libchat.git
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.convos.group_v1;
|
|
||||||
|
|
||||||
import "base.proto";
|
|
||||||
import "common_frames.proto";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message ConversationInvite_GroupV1 {
|
|
||||||
repeated string participants = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message GroupV1Frame {
|
|
||||||
// SDS like information: Message ID and channel_id extracted for utility
|
|
||||||
string message_id = 2;
|
|
||||||
string channel_id = 3; // Channel_id is associated with a set of participants
|
|
||||||
// This conflicts with conversation based encryption,
|
|
||||||
// need to ensure the derived sender is a valid participant
|
|
||||||
base.ReliabilityInfo reliability_info = 10;
|
|
||||||
|
|
||||||
oneof frame_type {
|
|
||||||
common_frames.ContentFrame content = 100;
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.encryption;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: This also encompasses plaintexts, is there a better name?
|
|
||||||
// Alternatives: ???
|
|
||||||
message EncryptedPayload {
|
|
||||||
|
|
||||||
oneof encryption {
|
|
||||||
encryption.Plaintext plaintext = 1;
|
|
||||||
encryption.Doubleratchet doubleratchet = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message Plaintext {
|
|
||||||
bytes payload=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Doubleratchet {
|
|
||||||
bytes dh = 1; // 32 byte array
|
|
||||||
uint32 msgNum = 2;
|
|
||||||
uint32 prevChainLen = 3;
|
|
||||||
bytes ciphertext = 4;
|
|
||||||
string aux = 5;
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.envelope;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Payload Framing Messages
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
message WapEnvelopeV1 {
|
|
||||||
|
|
||||||
string conversation_hint = 1;
|
|
||||||
uint64 salt = 2;
|
|
||||||
|
|
||||||
bytes payload = 5;
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.inbox;
|
|
||||||
|
|
||||||
import "invite.proto";
|
|
||||||
|
|
||||||
message Note{
|
|
||||||
string text = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message InboxV1Frame {
|
|
||||||
string recipient = 1;
|
|
||||||
oneof frame_type {
|
|
||||||
invite.InvitePrivateV1 invite_private_v1 = 10;
|
|
||||||
Note note = 11;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.invite;
|
|
||||||
|
|
||||||
import "encryption.proto";
|
|
||||||
|
|
||||||
message InvitePrivateV1 {
|
|
||||||
bytes initiator = 1;
|
|
||||||
bytes initiator_ephemeral = 2;
|
|
||||||
bytes participant = 3;
|
|
||||||
int32 participant_ephemeral_id= 4;
|
|
||||||
string discriminator = 5;
|
|
||||||
encryption.EncryptedPayload initial_message = 6;
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.convos.private_v1;
|
|
||||||
|
|
||||||
|
|
||||||
message Placeholder {
|
|
||||||
uint32 counter = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message PrivateV1Frame {
|
|
||||||
string conversation_id = 1;
|
|
||||||
bytes sender = 2;
|
|
||||||
int64 timestamp = 3; // Sender reported timestamp
|
|
||||||
oneof frame_type {
|
|
||||||
bytes content = 10;
|
|
||||||
Placeholder placeholder = 11;
|
|
||||||
// ....
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package wap.reliability;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// SDS Payloads
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
message HistoryEntry {
|
|
||||||
string message_id = 1; // Unique identifier of the SDS message, as defined in `Message`
|
|
||||||
bytes retrieval_hint = 2; // Optional information to help remote parties retrieve this SDS
|
|
||||||
// message; For example, A Waku deterministic message hash or routing payload hash
|
|
||||||
}
|
|
||||||
|
|
||||||
message ReliablePayload {
|
|
||||||
string message_id = 2;
|
|
||||||
string channel_id = 3;
|
|
||||||
int32 lamport_timestamp = 10;
|
|
||||||
repeated HistoryEntry causal_history = 11;
|
|
||||||
bytes bloom_filter = 12;
|
|
||||||
// Optional field causes errors in nim protobuf generation. Removing for now as optional is implied anways.
|
|
||||||
bytes content = 20;
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import naxolotl/[
|
|
||||||
naxolotl,
|
|
||||||
curve25519,
|
|
||||||
errors
|
|
||||||
]
|
|
||||||
|
|
||||||
export naxolotl, curve25519, NaxolotlError
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
import nim_chacha20_poly1305/[common, chacha20_poly1305, poly1305]
|
|
||||||
import std/[sysrand]
|
|
||||||
import results
|
|
||||||
import strformat
|
|
||||||
|
|
||||||
import types
|
|
||||||
import errors
|
|
||||||
|
|
||||||
|
|
||||||
proc encryptWithChaCha20Poly1305*(msgKey: MessageKey, plaintext: var openArray[byte], associatedData: openArray[byte]) : (Nonce, CipherText) =
|
|
||||||
|
|
||||||
var nonce : Nonce
|
|
||||||
discard urandom(nonce)
|
|
||||||
|
|
||||||
var tag: Tag
|
|
||||||
var ciphertext = newSeq[byte](plaintext.len + tag.len)
|
|
||||||
|
|
||||||
var counter : Counter = 0
|
|
||||||
|
|
||||||
# TODO: check plaintext mutability requirement
|
|
||||||
chacha20_aead_poly1305_encrypt(
|
|
||||||
Key(msgKey),
|
|
||||||
nonce,
|
|
||||||
counter,
|
|
||||||
associatedData,
|
|
||||||
plaintext,
|
|
||||||
ciphertext.toOpenArray(0, plaintext.high),
|
|
||||||
tag
|
|
||||||
)
|
|
||||||
|
|
||||||
# Combine tag with cipherkey for ease of transport and consistency with other implementations
|
|
||||||
copyMem(addr ciphertext[plaintext.len], unsafeAddr tag[0], tag.len)
|
|
||||||
(nonce, ciphertext)
|
|
||||||
|
|
||||||
|
|
||||||
proc decryptWithChaCha20Poly1305*(msgKey: MessageKey, nonce: Nonce, ciphertext: var openArray[byte], associatedData: openArray[byte]) : Result[seq[byte], NaxolotlError] =
|
|
||||||
var tag : Tag
|
|
||||||
if ciphertext.len <= tag.len:
|
|
||||||
return err(NaxolotlError(code: errInvalidInput, context: fmt"ciphertext is less than {tag.len} bytes. Expected `ciphertext || tag`" ))
|
|
||||||
|
|
||||||
copyMem(addr tag[0], unsafeAddr ciphertext[^tag.len], tag.len)
|
|
||||||
|
|
||||||
var plaintext = newSeq[byte](ciphertext.len - tag.len)
|
|
||||||
|
|
||||||
var computedTag: Tag
|
|
||||||
var counter : Counter = 0
|
|
||||||
|
|
||||||
chacha20_aead_poly1305_decrypt(
|
|
||||||
Key(msgKey),
|
|
||||||
nonce,
|
|
||||||
counter,
|
|
||||||
associatedData,
|
|
||||||
plaintext,
|
|
||||||
ciphertext.toOpenArray(0,ciphertext.high - tag.len),
|
|
||||||
computedTag
|
|
||||||
)
|
|
||||||
|
|
||||||
if not poly1305_verify(tag, computedTag):
|
|
||||||
return err(NaxolotlError(code: errMessageAuthentication, context: fmt"Got Tag: {tag} expected: {computedTag}"))
|
|
||||||
|
|
||||||
|
|
||||||
ok(plaintext)
|
|
||||||
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
# See https://github.com/vacp2p/nim-libp2p/blob/master/libp2p/crypto/curve25519.nim
|
|
||||||
|
|
||||||
import bearssl/[ec, rand]
|
|
||||||
import results
|
|
||||||
from stew/assign2 import assign
|
|
||||||
export results
|
|
||||||
|
|
||||||
const Curve25519KeySize* = 32
|
|
||||||
|
|
||||||
type
|
|
||||||
Curve25519* = object
|
|
||||||
Curve25519Key* = array[Curve25519KeySize, byte]
|
|
||||||
Curve25519Error* = enum
|
|
||||||
Curver25519GenError
|
|
||||||
|
|
||||||
proc intoCurve25519Key*(s: openArray[byte]): Curve25519Key =
|
|
||||||
assert s.len == Curve25519KeySize
|
|
||||||
assign(result, s)
|
|
||||||
|
|
||||||
proc getBytes*(key: Curve25519Key): seq[byte] =
|
|
||||||
@key
|
|
||||||
|
|
||||||
proc byteswap(buf: var Curve25519Key) {.inline.} =
|
|
||||||
for i in 0 ..< 16:
|
|
||||||
let x = buf[i]
|
|
||||||
buf[i] = buf[31 - i]
|
|
||||||
buf[31 - i] = x
|
|
||||||
|
|
||||||
proc mul*(_: type[Curve25519], point: var Curve25519Key, multiplier: Curve25519Key) =
|
|
||||||
let defaultBrEc = ecGetDefault()
|
|
||||||
|
|
||||||
# multiplier needs to be big-endian
|
|
||||||
var multiplierBs = multiplier
|
|
||||||
multiplierBs.byteswap()
|
|
||||||
let res = defaultBrEc.mul(
|
|
||||||
addr point[0],
|
|
||||||
Curve25519KeySize,
|
|
||||||
addr multiplierBs[0],
|
|
||||||
Curve25519KeySize,
|
|
||||||
EC_curve25519,
|
|
||||||
)
|
|
||||||
assert res == 1
|
|
||||||
|
|
||||||
proc mulgen(_: type[Curve25519], dst: var Curve25519Key, point: Curve25519Key) =
|
|
||||||
let defaultBrEc = ecGetDefault()
|
|
||||||
|
|
||||||
var rpoint = point
|
|
||||||
rpoint.byteswap()
|
|
||||||
|
|
||||||
let size =
|
|
||||||
defaultBrEc.mulgen(addr dst[0], addr rpoint[0], Curve25519KeySize, EC_curve25519)
|
|
||||||
|
|
||||||
assert size == Curve25519KeySize
|
|
||||||
|
|
||||||
proc public*(private: Curve25519Key): Curve25519Key =
|
|
||||||
Curve25519.mulgen(result, private)
|
|
||||||
|
|
||||||
proc random*(_: type[Curve25519Key], rng: var HmacDrbgContext): Curve25519Key =
|
|
||||||
var res: Curve25519Key
|
|
||||||
let defaultBrEc = ecGetDefault()
|
|
||||||
let len = ecKeygen(
|
|
||||||
PrngClassPointerConst(addr rng.vtable), defaultBrEc, nil, addr res[0], EC_curve25519
|
|
||||||
)
|
|
||||||
# Per bearssl documentation, the keygen only fails if the curve is
|
|
||||||
# unrecognised -
|
|
||||||
doAssert len == Curve25519KeySize, "Could not generate curve"
|
|
||||||
|
|
||||||
res
|
|
||||||
|
|
||||||
const FieldElementSize* = Curve25519KeySize
|
|
||||||
|
|
||||||
type FieldElement* = Curve25519Key
|
|
||||||
|
|
||||||
# Convert bytes to FieldElement
|
|
||||||
proc bytesToFieldElement*(bytes: openArray[byte]): Result[FieldElement, string] =
|
|
||||||
if bytes.len != FieldElementSize:
|
|
||||||
return err("Field element size must be 32 bytes")
|
|
||||||
ok(intoCurve25519Key(bytes))
|
|
||||||
|
|
||||||
# Convert FieldElement to bytes
|
|
||||||
proc fieldElementToBytes*(fe: FieldElement): seq[byte] =
|
|
||||||
fe.getBytes()
|
|
||||||
|
|
||||||
# Generate a random FieldElement
|
|
||||||
proc generateRandomFieldElement*(): Result[FieldElement, string] =
|
|
||||||
let rng = HmacDrbgContext.new()
|
|
||||||
if rng.isNil:
|
|
||||||
return err("Failed to creat HmacDrbgContext with system randomness")
|
|
||||||
ok(Curve25519Key.random(rng[]))
|
|
||||||
|
|
||||||
# Generate a key pair (private key and public key are both FieldElements)
|
|
||||||
proc generateKeyPair*(): Result[tuple[privateKey, publicKey: FieldElement], string] =
|
|
||||||
let privateKeyRes = generateRandomFieldElement()
|
|
||||||
if privateKeyRes.isErr:
|
|
||||||
return err(privateKeyRes.error)
|
|
||||||
let privateKey = privateKeyRes.get()
|
|
||||||
|
|
||||||
let publicKey = public(privateKey)
|
|
||||||
ok((privateKey, publicKey))
|
|
||||||
|
|
||||||
# # Multiply a given Curve25519 point with a set of scalars
|
|
||||||
# proc multiplyPointWithScalars*(
|
|
||||||
# point: FieldElement, scalars: openArray[FieldElement]
|
|
||||||
# ): FieldElement =
|
|
||||||
# var res = point
|
|
||||||
# for scalar in scalars:
|
|
||||||
# Curve25519.mul(res, scalar)
|
|
||||||
# res
|
|
||||||
|
|
||||||
# # Multiply the Curve25519 base point with a set of scalars
|
|
||||||
# proc multiplyBasePointWithScalars*(
|
|
||||||
# scalars: openArray[FieldElement]
|
|
||||||
# ): Result[FieldElement, string] =
|
|
||||||
# if scalars.len <= 0:
|
|
||||||
# return err("Atleast one scalar must be provided")
|
|
||||||
# var res: FieldElement = public(scalars[0]) # Use the predefined base point
|
|
||||||
# for i in 1 ..< scalars.len:
|
|
||||||
# Curve25519.mul(res, scalars[i]) # Multiply with each scalar
|
|
||||||
# ok(res)
|
|
||||||
|
|
||||||
# # Compare two FieldElements
|
|
||||||
# proc compareFieldElements*(a, b: FieldElement): bool =
|
|
||||||
# a == b
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
type
|
|
||||||
NaxolotlError* = object of CatchableError
|
|
||||||
code*: ErrorCode
|
|
||||||
context*: string
|
|
||||||
|
|
||||||
ErrorCode* = enum
|
|
||||||
errDecryption
|
|
||||||
errMessageAuthentication
|
|
||||||
errInvalidInput
|
|
||||||
errProgram
|
|
||||||
@ -1,210 +0,0 @@
|
|||||||
import curve25519
|
|
||||||
import results
|
|
||||||
import chronicles
|
|
||||||
import nim_chacha20_poly1305/common
|
|
||||||
import strformat
|
|
||||||
import strutils
|
|
||||||
import sequtils
|
|
||||||
import tables
|
|
||||||
|
|
||||||
import chacha
|
|
||||||
import types
|
|
||||||
import utils
|
|
||||||
import errors
|
|
||||||
|
|
||||||
const maxSkip = 10
|
|
||||||
|
|
||||||
|
|
||||||
type Doubleratchet* = object
|
|
||||||
dhSelf: PrivateKey
|
|
||||||
dhRemote: PublicKey
|
|
||||||
|
|
||||||
rootKey: RootKey
|
|
||||||
chainKeySend: ChainKey
|
|
||||||
chainKeyRecv: ChainKey
|
|
||||||
|
|
||||||
msgCountSend: MsgCount
|
|
||||||
msgCountRecv: MsgCount
|
|
||||||
prevChainLen: MsgCount
|
|
||||||
|
|
||||||
# TODO: SkippedKeys
|
|
||||||
skippedMessageKeys: Table[(PublicKey,MsgCount), MessageKey]
|
|
||||||
|
|
||||||
const DomainSepKdfRoot = "DoubleRatchetRootKey"
|
|
||||||
|
|
||||||
|
|
||||||
type DrHeader* = object
|
|
||||||
dhPublic*: PublicKey
|
|
||||||
msgNumber*: uint32
|
|
||||||
prevChainLen*: uint32
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func keyId(dh:PublicKey, recvCount: MsgCount ): KeyId =
|
|
||||||
(dh, recvCount)
|
|
||||||
|
|
||||||
func hex(a: openArray[byte]) : string =
|
|
||||||
a.mapIt(&"{it:02X}").join("")
|
|
||||||
|
|
||||||
proc `$`*(x: DrHeader): string =
|
|
||||||
"DrHeader(pubKey=" & hex(x.dhPublic) & ", msgNum=" & $x.msgNumber & ", msgNum=" & $x.prevChainLen & ")"
|
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(key: array[32, byte]): string =
|
|
||||||
let byteStr = hex(key)
|
|
||||||
fmt"{byteStr[0..5]}..{byteStr[^6 .. ^1]}"
|
|
||||||
|
|
||||||
|
|
||||||
proc generateDhKey() : PrivateKey =
|
|
||||||
result = generateKeypair().get()[0]
|
|
||||||
|
|
||||||
#################################################
|
|
||||||
# Kdf
|
|
||||||
#################################################
|
|
||||||
|
|
||||||
|
|
||||||
func kdfRoot(rootKey: RootKey, dhOutput:DhDerivedKey): (RootKey, ChainKey) =
|
|
||||||
|
|
||||||
var salt = rootKey
|
|
||||||
var ikm = dhOutput
|
|
||||||
let info = cast[seq[byte]](DomainSepKdfRoot)
|
|
||||||
|
|
||||||
hkdfSplit(salt, ikm, info)
|
|
||||||
|
|
||||||
func kdfChain(chainKey: ChainKey): (MessageKey, ChainKey) =
|
|
||||||
|
|
||||||
let msgKey = hkdfExtract(chainKey, [0x01u8])
|
|
||||||
let chainKey = hkdfExtract(chainKey, [0x02u8])
|
|
||||||
|
|
||||||
return(msgKey, chainKey)
|
|
||||||
|
|
||||||
func dhRatchetSend(self: var Doubleratchet) =
|
|
||||||
# Perform DH Ratchet step when receiving a new peer key.
|
|
||||||
let dhOutput : DhDerivedKey = dhExchange(self.dhSelf, self.dhRemote).get()
|
|
||||||
let (newRootKey, newChainKeySend) = kdfRoot(self.rootKey, dhOutput)
|
|
||||||
self.rootKey = newRootKey
|
|
||||||
self.chainKeySend = newChainKeySend
|
|
||||||
self.msgCountSend = 0
|
|
||||||
|
|
||||||
proc dhRatchetRecv(self: var Doubleratchet, remotePublickey: PublicKey ) =
|
|
||||||
self.prevChainLen = self.msgCountSend
|
|
||||||
self.msgCountSend = 0
|
|
||||||
self.msgCountRecv = 0
|
|
||||||
|
|
||||||
self.dhRemote = remotePublickey
|
|
||||||
|
|
||||||
let dhOutputPre = self.dhSelf.dhExchange(self.dhRemote).get()
|
|
||||||
let (newRootKey, newChainKeyRecv) = kdfRoot(self.rootKey, dhOutputPre)
|
|
||||||
self.rootKey = newRootKey
|
|
||||||
self.chainKeyRecv = newChainKeyRecv
|
|
||||||
|
|
||||||
self.dhSelf = generateDhKey()
|
|
||||||
|
|
||||||
let dhOutputPost = self.dhSelf.dhExchange(self.dhRemote).get()
|
|
||||||
(self.rootKey, self.chainKeySend) = kdfRoot(self.rootKey, dhOutputPost)
|
|
||||||
|
|
||||||
|
|
||||||
proc skipMessageKeys(self: var Doubleratchet, until: MsgCount): Result[(), string] =
|
|
||||||
|
|
||||||
if self.msgCountRecv + maxSkip < until:
|
|
||||||
return err("Too many skipped messages")
|
|
||||||
|
|
||||||
while self.msgCountRecv < until:
|
|
||||||
let (msgKey, chainKey) = kdfChain(self.chainKeyRecv)
|
|
||||||
self.chainKeyRecv = chainKey
|
|
||||||
|
|
||||||
let keyId = keyId(self.dhRemote, self.msgCountRecv)
|
|
||||||
self.skippedMessageKeys[keyId] = msgKey
|
|
||||||
inc self.msgCountRecv
|
|
||||||
|
|
||||||
ok(())
|
|
||||||
|
|
||||||
proc encrypt(self: var Doubleratchet, plaintext: var seq[byte], associatedData: openArray[byte]): (DrHeader, CipherText) =
|
|
||||||
|
|
||||||
let (msgKey, chainKey) = kdfChain(self.chainKeySend)
|
|
||||||
self.chainKeySend = chainKey
|
|
||||||
let header = DrHeader(
|
|
||||||
dhPublic: self.dhSelf.public, #TODO Serialize
|
|
||||||
msgNumber: self.msgCountSend,
|
|
||||||
prevChainLen: self.prevChainLen)
|
|
||||||
|
|
||||||
self.msgCountSend = self.msgCountSend + 1
|
|
||||||
|
|
||||||
|
|
||||||
var (nonce, ciphertext) = encryptWithChaCha20Poly1305(msgKey, plaintext, associatedData)
|
|
||||||
|
|
||||||
# TODO: optimize copies
|
|
||||||
var output : seq[byte]
|
|
||||||
output.add(nonce)
|
|
||||||
output.add(ciphertext)
|
|
||||||
|
|
||||||
(header, output)
|
|
||||||
|
|
||||||
|
|
||||||
proc decrypt*(self: var Doubleratchet, header: DrHeader, ciphertext: CipherText, associatedData: openArray[byte] ) : Result[seq[byte], NaxolotlError] =
|
|
||||||
|
|
||||||
let peerPublic = header.dhPublic
|
|
||||||
var msgKey : MessageKey
|
|
||||||
|
|
||||||
# Check Skipped Keys
|
|
||||||
let keyId = keyId(header.dhPublic, header.msgNumber)
|
|
||||||
if self.skippedMessageKeys.hasKey(keyId):
|
|
||||||
debug "detected skipped message", keyId = keyId
|
|
||||||
msgKey = self.skippedMessageKeys[keyId]
|
|
||||||
else:
|
|
||||||
if (peerPublic != self.dhRemote):
|
|
||||||
let r = self.skipMessageKeys(header.prevChainLen)
|
|
||||||
if r.isErr:
|
|
||||||
error "skipMessages", error = r.error()
|
|
||||||
self.dhRatchetRecv(peerPublic)
|
|
||||||
let r = self.skipMessageKeys(header.msgNumber)
|
|
||||||
if r.isErr:
|
|
||||||
error "skipMessages", error = r.error()
|
|
||||||
|
|
||||||
(msgKey, self.chainKeyRecv) = kdfChain(self.chainKeyRecv)
|
|
||||||
inc self.msgCountRecv
|
|
||||||
|
|
||||||
var nonce : Nonce
|
|
||||||
copyMem(addr nonce[0], unsafeAddr ciphertext[0], Nonce.len)
|
|
||||||
var cipherTag = ciphertext[Nonce.len .. ^1]
|
|
||||||
|
|
||||||
result = decryptWithChaCha20Poly1305(msgKey,nonce, cipherTag, associatedData )
|
|
||||||
|
|
||||||
if result.isOk:
|
|
||||||
# TODO: persist chainKey state changes
|
|
||||||
self.skippedMessageKeys.del(keyId)
|
|
||||||
|
|
||||||
|
|
||||||
proc encrypt*(self: var Doubleratchet, plaintext: var seq[byte]) : (DrHeader, CipherText) =
|
|
||||||
encrypt(self, plaintext,@[])
|
|
||||||
|
|
||||||
|
|
||||||
proc initDoubleratchetSender*(sharedSecret: array[32, byte], dhRemote: PublicKey): Doubleratchet =
|
|
||||||
|
|
||||||
result = Doubleratchet(
|
|
||||||
dhSelf: generateDhKey(),
|
|
||||||
dhRemote: dhRemote,
|
|
||||||
rootKey: RootKey(sharedSecret),
|
|
||||||
msgCountSend: 0,
|
|
||||||
msgCountRecv: 0,
|
|
||||||
prevChainLen: 0,
|
|
||||||
skippedMessageKeys: initTable[(PublicKey, MsgCount), MessageKey]()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Update RK, CKs
|
|
||||||
result.dhRatchetSend()
|
|
||||||
|
|
||||||
proc initDoubleratchetRecipient*(sharedSecret: array[32, byte], dhSelf: PrivateKey): Doubleratchet =
|
|
||||||
|
|
||||||
result = Doubleratchet(
|
|
||||||
dhSelf: dhSelf,
|
|
||||||
#dhRemote: None,
|
|
||||||
rootKey: RootKey(sharedSecret),
|
|
||||||
msgCountSend: 0,
|
|
||||||
msgCountRecv: 0,
|
|
||||||
prevChainLen: 0,
|
|
||||||
skippedMessageKeys: initTable[(PublicKey, MsgCount), MessageKey]()
|
|
||||||
)
|
|
||||||
|
|
||||||
func dhSelfPublic*(self: Doubleratchet): PublicKey =
|
|
||||||
self.dhSelf.public
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
import curve25519
|
|
||||||
|
|
||||||
type PrivateKey* = Curve25519Key
|
|
||||||
type PublicKey* = Curve25519Key
|
|
||||||
|
|
||||||
type RootKey* = array[32, byte]
|
|
||||||
type ChainKey* = array[32, byte]
|
|
||||||
type MessageKey* = array[32, byte]
|
|
||||||
type DhDerivedKey* = array[32, byte]
|
|
||||||
|
|
||||||
type GenericArray* = array[32, byte]
|
|
||||||
|
|
||||||
type CipherText* = seq[byte]
|
|
||||||
|
|
||||||
type MsgCount* = uint32
|
|
||||||
type KeyId* = (PublicKey, MsgCount)
|
|
||||||
|
|
||||||
const KeyLen* = 32
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
import constantine/hashes
|
|
||||||
import constantine/kdf/kdf_hkdf
|
|
||||||
import curve25519
|
|
||||||
import results
|
|
||||||
|
|
||||||
import errors
|
|
||||||
import types
|
|
||||||
|
|
||||||
|
|
||||||
func hkdfExtract*(key: openArray[byte], seed: openArray[byte]) : GenericArray =
|
|
||||||
|
|
||||||
assert GenericArray.len == sha256.digestSize()
|
|
||||||
|
|
||||||
var ctx{.noInit.}: HKDF[sha256]
|
|
||||||
var prk{.noInit.}: array[sha256.digestSize(), byte]
|
|
||||||
ctx.hkdfExtract(prk, key, seed)
|
|
||||||
|
|
||||||
return prk
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func hkdfExtractExpand*(output: var openArray[byte], salt: openArray[byte], ikm: openArray[byte], info: openArray[byte] ) =
|
|
||||||
var ctx{.noInit.}: HKDF[sha256]
|
|
||||||
var prk{.noInit.}: array[sha256.digestSize(), byte]
|
|
||||||
ctx.hkdfExtract(prk, salt, ikm)
|
|
||||||
ctx.hkdfExpand(output, prk, info, true)
|
|
||||||
|
|
||||||
|
|
||||||
func hkdfSplit*(salt: GenericArray, ikm: GenericArray, info: openArray[byte] ) : (RootKey, ChainKey) =
|
|
||||||
|
|
||||||
var output : array[KeyLen*2 , byte]
|
|
||||||
|
|
||||||
hkdfExtractExpand(output, salt, ikm, info)
|
|
||||||
|
|
||||||
var out1 : array[KeyLen, byte]
|
|
||||||
var out2 : array[KeyLen, byte]
|
|
||||||
|
|
||||||
# Unsafe memcopy
|
|
||||||
copyMem(addr out1[0], addr output[0], KeyLen)
|
|
||||||
copyMem(addr out2[0], addr output[32], KeyLen)
|
|
||||||
|
|
||||||
result = (out1,out2)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func dhExchange*(a: PrivateKey, b: PublicKey): Result[DhDerivedKey, NaxolotlError] =
|
|
||||||
var dhOuput = b
|
|
||||||
|
|
||||||
try:
|
|
||||||
Curve25519.mul(dhOuput, a)
|
|
||||||
except CatchableError as e:
|
|
||||||
return err(NaxolotlError( code: errProgram, context: e.msg))
|
|
||||||
ok(DhDerivedKey(dhOuput))
|
|
||||||
|
|
||||||
|
|
||||||
1
vendor/constantine
vendored
1
vendor/constantine
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit d6aae1eca3775d6317e11b169edef0249162ce22
|
|
||||||
1
vendor/illwill
vendored
1
vendor/illwill
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 99a120f7f69868b94f5d35ce7e21dd12535de70c
|
|
||||||
1
vendor/nim-ffi
vendored
1
vendor/nim-ffi
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 06111de155253b34e47ed2aaed1d61d08d62cc1b
|
|
||||||
1
vendor/nim-sds
vendored
1
vendor/nim-sds
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 6a05cfd2c954886ebbe46adb222ecc1dc9117fd0
|
|
||||||
1
vendor/nim_chacha20_poly1305
vendored
1
vendor/nim_chacha20_poly1305
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit ad06aff319bdb5d61cebd56d2d0e31c3516112c6
|
|
||||||
Loading…
x
Reference in New Issue
Block a user