separate out crypto utils

This commit is contained in:
Adhiraj Singh
2021-09-23 22:37:33 +05:30
parent f267f27ada
commit f1527a9f6b
13 changed files with 131 additions and 131 deletions

View File

@@ -78,9 +78,10 @@ If the connection is successful, you will see a QR code printed on your terminal
## Notable Differences Between Baileys Web & MD ## Notable Differences Between Baileys Web & MD
1. Baileys no longer maintains an internal state of chats/contacts/messages. You must take this on your own, simply because your state in MD is its own source of truth & there is no one-size-fits-all way to handle the storage for this. 1. Baileys has been written from the ground up to have a more "functional" structure. This is done primarily for simplicity & more testability
2. A baileys "socket" is meant to be a temporary & disposable object -- this is done to maintain simplicity & prevent bugs. I felt the entire Baileys object became too bloated as it supported too many configurations. 2. Baileys no longer maintains an internal state of chats/contacts/messages. You must take this on your own, simply because your state in MD is its own source of truth & there is no one-size-fits-all way to handle the storage for this.
3. Moreover, Baileys does not offer an inbuilt reconnect mechanism anymore (though it's super easy to set one up on your own with your own rules, check the example script) 3. A baileys "socket" is meant to be a temporary & disposable object -- this is done to maintain simplicity & prevent bugs. I felt the entire Baileys object became too bloated as it supported too many configurations. You're encouraged to write your own implementation to handle missing functionality.
4. Moreover, Baileys does not offer an inbuilt reconnect mechanism anymore (though it's super easy to set one up on your own with your own rules, check the example script)
## Configuring the Connection ## Configuring the Connection

View File

@@ -4,7 +4,7 @@ import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, jidNormalizedUse
import { makeSocket } from "./socket"; import { makeSocket } from "./socket";
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import { toNumber } from "../Utils/generics"; import { toNumber } from "../Utils/generics";
import { compressImage, generateProfilePicture } from ".."; import { generateProfilePicture } from "../Utils";
export const makeChatsSocket = (config: SocketConfig) => { export const makeChatsSocket = (config: SocketConfig) => {
const { logger } = config const { logger } = config

View File

@@ -1,8 +1,8 @@
import { makeGroupsSocket } from "./groups" import { makeGroupsSocket } from "./groups"
import { SocketConfig, WAMessageStubType, ParticipantAction, Chat, GroupMetadata } from "../Types" import { SocketConfig, WAMessageStubType, ParticipantAction, Chat, GroupMetadata } from "../Types"
import { decodeMessageStanza, encodeBigEndian, toNumber, whatsappID } from "../Utils" import { decodeMessageStanza, encodeBigEndian, toNumber } from "../Utils"
import { BinaryNode, jidDecode, jidEncode, isJidStatusBroadcast, S_WHATSAPP_NET, areJidsSameUser, getBinaryNodeChildren, getBinaryNodeChild } from '../WABinary' import { BinaryNode, jidDecode, jidEncode, isJidStatusBroadcast, areJidsSameUser, getBinaryNodeChildren } from '../WABinary'
import { downloadIfHistory } from '../Utils/history' import { downloadIfHistory } from '../Utils/history'
import { proto } from "../../WAProto" import { proto } from "../../WAProto"
import { generateSignalPubKey, xmppPreKey, xmppSignedPreKey } from "../Utils/signal" import { generateSignalPubKey, xmppPreKey, xmppSignedPreKey } from "../Utils/signal"
@@ -139,7 +139,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
switch (message.messageStubType) { switch (message.messageStubType) {
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE: case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE: case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
participants = message.messageStubParameters.map(whatsappID) participants = message.messageStubParameters
emitParticipantsUpdate('remove') emitParticipantsUpdate('remove')
// mark the chat read only if you left the group // mark the chat read only if you left the group
if (participants.includes(meJid)) { if (participants.includes(meJid)) {
@@ -149,7 +149,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
case WAMessageStubType.GROUP_PARTICIPANT_ADD: case WAMessageStubType.GROUP_PARTICIPANT_ADD:
case WAMessageStubType.GROUP_PARTICIPANT_INVITE: case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN: case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
participants = message.messageStubParameters.map(whatsappID) participants = message.messageStubParameters
if (participants.includes(meJid)) { if (participants.includes(meJid)) {
chatUpdate.readOnly = false chatUpdate.readOnly = false
} }

View File

@@ -5,7 +5,7 @@ import WebSocket from "ws"
import { randomBytes } from 'crypto' import { randomBytes } from 'crypto'
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import { DisconnectReason, SocketConfig, BaileysEventEmitter } from "../Types" import { DisconnectReason, SocketConfig, BaileysEventEmitter } from "../Types"
import { generateCurveKeyPair, initAuthState, generateRegistrationNode, configureSuccessfulPairing, generateLoginNode, encodeBigEndian, promiseTimeout } from "../Utils" import { Curve, initAuthState, generateRegistrationNode, configureSuccessfulPairing, generateLoginNode, encodeBigEndian, promiseTimeout } from "../Utils"
import { DEFAULT_ORIGIN, DEF_TAG_PREFIX, DEF_CALLBACK_PREFIX, KEY_BUNDLE_TYPE } from "../Defaults" import { DEFAULT_ORIGIN, DEF_TAG_PREFIX, DEF_CALLBACK_PREFIX, KEY_BUNDLE_TYPE } from "../Defaults"
import { assertNodeErrorFree, BinaryNode, encodeBinaryNode, S_WHATSAPP_NET } from '../WABinary' import { assertNodeErrorFree, BinaryNode, encodeBinaryNode, S_WHATSAPP_NET } from '../WABinary'
import noiseHandler from '../Utils/noise-handler' import noiseHandler from '../Utils/noise-handler'
@@ -42,7 +42,7 @@ export const makeSocket = ({
}) })
ws.setMaxListeners(0) ws.setMaxListeners(0)
/** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */ /** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
const ephemeralKeyPair = generateCurveKeyPair() const ephemeralKeyPair = Curve.generateKeyPair()
/** WA noise protocol wrapper */ /** WA noise protocol wrapper */
const noise = noiseHandler(ephemeralKeyPair) const noise = noiseHandler(ephemeralKeyPair)
const authState = initialAuthState || initAuthState() const authState = initialAuthState || initAuthState()

View File

@@ -1,5 +1,5 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import { aesDecrypt, hmacSign, aesEncrypt, hkdf } from "./generics" import { aesDecrypt, hmacSign, aesEncrypt, hkdf } from "./crypto"
import { AuthenticationState, ChatModification } from "../Types" import { AuthenticationState, ChatModification } from "../Types"
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import { LT_HASH_ANTI_TAMPERING } from '../WABinary/LTHash' import { LT_HASH_ANTI_TAMPERING } from '../WABinary/LTHash'

100
src/Utils/crypto.ts Normal file
View File

@@ -0,0 +1,100 @@
import CurveCrypto from 'libsignal/src/curve25519_wrapper'
import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto'
import { KeyPair } from '../Types'
export const Curve = {
generateKeyPair: (): KeyPair => {
const { pubKey, privKey } = CurveCrypto.keyPair(randomBytes(32))
return {
private: Buffer.from(privKey),
public: Buffer.from(pubKey)
}
},
sharedKey: (privateKey: Uint8Array, publicKey: Uint8Array) => {
const shared = CurveCrypto.sharedSecret(publicKey, privateKey)
return Buffer.from(shared)
},
sign: (privateKey: Uint8Array, buf: Uint8Array) => (
Buffer.from(CurveCrypto.sign(privateKey, buf))
),
verify: (pubKey: Uint8Array, message: Uint8Array, signature: Uint8Array) => {
try {
CurveCrypto.verify(pubKey, message, signature)
return true
} catch(error) {
if(error.message.includes('Invalid')) {
return false
}
throw error
}
}
}
export const signedKeyPair = (keyPair: KeyPair, keyId: number) => {
const signKeys = Curve.generateKeyPair()
const pubKey = new Uint8Array(33)
pubKey.set([5], 0)
pubKey.set(signKeys.public, 1)
const signature = Curve.sign(keyPair.private, pubKey)
return { keyPair: signKeys, signature, keyId }
}
/** decrypt AES 256 CBC; where the IV is prefixed to the buffer */
export function aesDecrypt(buffer: Buffer, key: Buffer) {
return aesDecryptWithIV(buffer.slice(16, buffer.length), key, buffer.slice(0, 16))
}
/** decrypt AES 256 CBC */
export function aesDecryptWithIV(buffer: Buffer, key: Buffer, IV: Buffer) {
const aes = createDecipheriv('aes-256-cbc', key, IV)
return Buffer.concat([aes.update(buffer), aes.final()])
}
// encrypt AES 256 CBC; where a random IV is prefixed to the buffer
export function aesEncrypt(buffer: Buffer | Uint8Array, key: Buffer) {
const IV = randomBytes(16)
const aes = createCipheriv('aes-256-cbc', key, IV)
return Buffer.concat([IV, aes.update(buffer), aes.final()]) // prefix IV to the buffer
}
// encrypt AES 256 CBC with a given IV
export function aesEncrypWithIV(buffer: Buffer, key: Buffer, IV: Buffer) {
const aes = createCipheriv('aes-256-cbc', key, IV)
return Buffer.concat([aes.update(buffer), aes.final()]) // prefix IV to the buffer
}
// sign HMAC using SHA 256
export function hmacSign(buffer: Buffer | Uint8Array, key: Buffer | Uint8Array, variant: 'sha256' | 'sha512' = 'sha256') {
return createHmac(variant, key).update(buffer).digest()
}
export function sha256(buffer: Buffer) {
return createHash('sha256').update(buffer).digest()
}
// HKDF key expansion
// from: https://github.com/benadida/node-hkdf
export function hkdf(buffer: Buffer, expandedLength: number, { info, salt }: { salt?: Buffer, info?: string }) {
const hashAlg = 'sha256'
const hashLength = 32
salt = salt || Buffer.alloc(hashLength)
// now we compute the PRK
const prk = createHmac(hashAlg, salt).update(buffer).digest()
let prev = Buffer.from([])
const buffers = []
const num_blocks = Math.ceil(expandedLength / hashLength)
const infoBuff = Buffer.from(info || [])
for (var i=0; i<num_blocks; i++) {
const hmac = createHmac(hashAlg, prk)
// XXX is there a more optimal way to build up buffers?
const input = Buffer.concat([
prev,
infoBuff,
Buffer.from(String.fromCharCode(i + 1))
]);
hmac.update(input)
prev = hmac.digest()
buffers.push(prev)
}
return Buffer.concat(buffers, expandedLength)
}

View File

@@ -1,8 +1,6 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import CurveCrypto from 'libsignal/src/curve25519_wrapper' import { randomBytes } from 'crypto'
import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto'
import { platform, release } from 'os' import { platform, release } from 'os'
import { KeyPair } from '../Types'
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import { Binary } from '../WABinary' import { Binary } from '../WABinary'
@@ -71,46 +69,6 @@ export const encodeWAMessage = (message: proto.IMessage) => (
) )
) )
export const generateCurveKeyPair = (): KeyPair => {
const { pubKey, privKey } = CurveCrypto.keyPair(randomBytes(32))
return {
private: Buffer.from(privKey),
public: Buffer.from(pubKey)
}
}
export const generateSharedKey = (privateKey: Uint8Array, publicKey: Uint8Array) => {
const shared = CurveCrypto.sharedSecret(publicKey, privateKey)
return Buffer.from(shared)
}
export const curveSign = (privateKey: Uint8Array, buf: Uint8Array) => (
Buffer.from(CurveCrypto.sign(privateKey, buf))
)
export const curveVerify = (pubKey: Uint8Array, message: Uint8Array, signature: Uint8Array) => {
try {
CurveCrypto.verify(pubKey, message, signature)
return true
} catch(error) {
if(error.message.includes('Invalid')) {
return false
}
throw error
}
}
export const signedKeyPair = (keyPair: KeyPair, keyId: number) => {
const signKeys = generateCurveKeyPair()
const pubKey = new Uint8Array(33)
pubKey.set([5], 0)
pubKey.set(signKeys.public, 1)
const signature = curveSign(keyPair.private, pubKey)
return { keyPair: signKeys, signature, keyId }
}
export const generateRegistrationId = () => ( export const generateRegistrationId = () => (
Uint16Array.from(randomBytes(2))[0] & 0x3fff Uint16Array.from(randomBytes(2))[0] & 0x3fff
) )
@@ -134,9 +92,6 @@ export const encodeBigEndian = (e: number, t=4) => {
export const toNumber = (t: Long | number) => (typeof t?.['low'] !== 'undefined' ? t['low'] : t) as number export const toNumber = (t: Long | number) => (typeof t?.['low'] !== 'undefined' ? t['low'] : t) as number
export const whatsappID = (jid: string) => jid?.replace ('@c.us', '@s.whatsapp.net')
export const isGroupID = (jid: string) => jid?.endsWith ('@g.us')
export function shallowChanges <T> (old: T, current: T, {lookForDeletedKeys}: {lookForDeletedKeys: boolean}): Partial<T> { export function shallowChanges <T> (old: T, current: T, {lookForDeletedKeys}: {lookForDeletedKeys: boolean}): Partial<T> {
let changes: Partial<T> = {} let changes: Partial<T> = {}
for (let key in current) { for (let key in current) {
@@ -153,64 +108,6 @@ export function shallowChanges <T> (old: T, current: T, {lookForDeletedKeys}: {l
} }
return changes return changes
} }
/** decrypt AES 256 CBC; where the IV is prefixed to the buffer */
export function aesDecrypt(buffer: Buffer, key: Buffer) {
return aesDecryptWithIV(buffer.slice(16, buffer.length), key, buffer.slice(0, 16))
}
/** decrypt AES 256 CBC */
export function aesDecryptWithIV(buffer: Buffer, key: Buffer, IV: Buffer) {
const aes = createDecipheriv('aes-256-cbc', key, IV)
return Buffer.concat([aes.update(buffer), aes.final()])
}
// encrypt AES 256 CBC; where a random IV is prefixed to the buffer
export function aesEncrypt(buffer: Buffer | Uint8Array, key: Buffer) {
const IV = randomBytes(16)
const aes = createCipheriv('aes-256-cbc', key, IV)
return Buffer.concat([IV, aes.update(buffer), aes.final()]) // prefix IV to the buffer
}
// encrypt AES 256 CBC with a given IV
export function aesEncrypWithIV(buffer: Buffer, key: Buffer, IV: Buffer) {
const aes = createCipheriv('aes-256-cbc', key, IV)
return Buffer.concat([aes.update(buffer), aes.final()]) // prefix IV to the buffer
}
// sign HMAC using SHA 256
export function hmacSign(buffer: Buffer | Uint8Array, key: Buffer | Uint8Array, variant: 'sha256' | 'sha512' = 'sha256') {
return createHmac(variant, key).update(buffer).digest()
}
export function sha256(buffer: Buffer) {
return createHash('sha256').update(buffer).digest()
}
// HKDF key expansion
// from: https://github.com/benadida/node-hkdf
export function hkdf(buffer: Buffer, expandedLength: number, { info, salt }: { salt?: Buffer, info?: string }) {
const hashAlg = 'sha256'
const hashLength = 32
salt = salt || Buffer.alloc(hashLength)
// now we compute the PRK
const prk = createHmac(hashAlg, salt).update(buffer).digest()
let prev = Buffer.from([])
const buffers = []
const num_blocks = Math.ceil(expandedLength / hashLength)
const infoBuff = Buffer.from(info || [])
for (var i=0; i<num_blocks; i++) {
const hmac = createHmac(hashAlg, prk)
// XXX is there a more optimal way to build up buffers?
const input = Buffer.concat([
prev,
infoBuff,
Buffer.from(String.fromCharCode(i + 1))
]);
hmac.update(input)
prev = hmac.digest()
buffers.push(prev)
}
return Buffer.concat(buffers, expandedLength)
}
/** unix timestamp of a date in seconds */ /** unix timestamp of a date in seconds */
export const unixTimestampSeconds = (date: Date = new Date()) => Math.floor(date.getTime()/1000) export const unixTimestampSeconds = (date: Date = new Date()) => Math.floor(date.getTime()/1000)

View File

@@ -2,4 +2,5 @@ export * from './decode-wa-message'
export * from './generics' export * from './generics'
export * from './messages' export * from './messages'
export * from './messages-media' export * from './messages-media'
export * from './validate-connection' export * from './validate-connection'
export * from './crypto'

View File

@@ -11,7 +11,8 @@ import { join } from 'path'
import { once } from 'events' import { once } from 'events'
import got, { Options, Response } from 'got' import got, { Options, Response } from 'got'
import { MessageType, WAMessageContent, WAProto, WAGenericMediaMessage, WAMediaUpload, MediaType } from '../Types' import { MessageType, WAMessageContent, WAProto, WAGenericMediaMessage, WAMediaUpload, MediaType } from '../Types'
import { generateMessageID, hkdf } from './generics' import { generateMessageID } from './generics'
import { hkdf } from './crypto'
import { DEFAULT_ORIGIN } from '../Defaults' import { DEFAULT_ORIGIN } from '../Defaults'
export const hkdfInfoKey = (type: MediaType) => { export const hkdfInfoKey = (type: MediaType) => {

View File

@@ -18,7 +18,7 @@ import {
MediaType, MediaType,
WAMessageStatus WAMessageStatus
} from "../Types" } from "../Types"
import { generateMessageID, unixTimestampSeconds, whatsappID } from "./generics" import { generateMessageID, unixTimestampSeconds } from "./generics"
import { encryptedStream, generateThumbnail, getAudioDuration } from "./messages-media" import { encryptedStream, generateThumbnail, getAudioDuration } from "./messages-media"
type MediaUploadData = { type MediaUploadData = {
@@ -268,8 +268,6 @@ export const generateWAMessageFromContent = (
options: MessageGenerationOptionsFromContent options: MessageGenerationOptionsFromContent
) => { ) => {
if (!options.timestamp) options.timestamp = new Date() // set timestamp to now if (!options.timestamp) options.timestamp = new Date() // set timestamp to now
// prevent an annoying bug (WA doesn't accept sending messages with '@c.us')
jid = whatsappID(jid)
const key = Object.keys(message)[0] const key = Object.keys(message)[0]
const timestamp = unixTimestampSeconds(options.timestamp) const timestamp = unixTimestampSeconds(options.timestamp)

View File

@@ -1,4 +1,4 @@
import { sha256, generateSharedKey, hkdf } from "./generics"; import { sha256, Curve, hkdf } from "./crypto";
import { Binary } from "../WABinary"; import { Binary } from "../WABinary";
import { createCipheriv, createDecipheriv } from "crypto"; import { createCipheriv, createDecipheriv } from "crypto";
import { NOISE_MODE, NOISE_WA_HEADER } from "../Defaults"; import { NOISE_MODE, NOISE_WA_HEADER } from "../Defaults";
@@ -100,10 +100,10 @@ export default ({ public: publicKey, private: privateKey }: KeyPair) => {
finishInit, finishInit,
processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => { processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => {
authenticate(serverHello!.ephemeral!) authenticate(serverHello!.ephemeral!)
mixIntoKey(generateSharedKey(privateKey, serverHello.ephemeral!)) mixIntoKey(Curve.sharedKey(privateKey, serverHello.ephemeral!))
const decStaticContent = decrypt(serverHello!.static!) const decStaticContent = decrypt(serverHello!.static!)
mixIntoKey(generateSharedKey(privateKey, decStaticContent)) mixIntoKey(Curve.sharedKey(privateKey, decStaticContent))
const certDecoded = decrypt(serverHello!.payload!) const certDecoded = decrypt(serverHello!.payload!)
const { details: certDetails, signature: certSignature } = proto.NoiseCertificate.decode(certDecoded) const { details: certDetails, signature: certSignature } = proto.NoiseCertificate.decode(certDecoded)
@@ -115,7 +115,7 @@ export default ({ public: publicKey, private: privateKey }: KeyPair) => {
} }
const keyEnc = encrypt(noiseKey.public) const keyEnc = encrypt(noiseKey.public)
mixIntoKey(generateSharedKey(noiseKey.private, serverHello!.ephemeral!)) mixIntoKey(Curve.sharedKey(noiseKey.private, serverHello!.ephemeral!))
return keyEnc return keyEnc
}, },

View File

@@ -1,5 +1,6 @@
import * as libsignal from 'libsignal' import * as libsignal from 'libsignal'
import { encodeBigEndian, generateCurveKeyPair } from "./generics" import { encodeBigEndian } from "./generics"
import { Curve } from "./crypto"
import { SenderKeyDistributionMessage, GroupSessionBuilder, SenderKeyRecord, SenderKeyName, GroupCipher } from '../../WASignalGroup' import { SenderKeyDistributionMessage, GroupSessionBuilder, SenderKeyRecord, SenderKeyName, GroupCipher } from '../../WASignalGroup'
import { SignalIdentity, SignalKeyStore, SignedKeyPair, KeyPair, AuthenticationState } from "../Types/Auth" import { SignalIdentity, SignalKeyStore, SignedKeyPair, KeyPair, AuthenticationState } from "../Types/Auth"
import { assertNodeErrorFree, BinaryNode, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildUInt, jidDecode } from "../WABinary" import { assertNodeErrorFree, BinaryNode, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildUInt, jidDecode } from "../WABinary"
@@ -48,7 +49,7 @@ export const generateOrGetPreKeys = ({ creds }: AuthenticationState, range: numb
const newPreKeys: { [id: number]: KeyPair } = { } const newPreKeys: { [id: number]: KeyPair } = { }
if(remaining > 0) { if(remaining > 0) {
for(let i = creds.nextPreKeyId;i <= lastPreKeyId;i++) { for(let i = creds.nextPreKeyId;i <= lastPreKeyId;i++) {
newPreKeys[i] = generateCurveKeyPair() newPreKeys[i] = Curve.generateKeyPair()
} }
} }
return { return {

View File

@@ -2,7 +2,8 @@ import { Boom } from '@hapi/boom'
import { randomBytes } from 'crypto' import { randomBytes } from 'crypto'
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import type { AuthenticationState, SocketConfig, SignalKeyStore, AuthenticationCreds, KeyPair } from "../Types" import type { AuthenticationState, SocketConfig, SignalKeyStore, AuthenticationCreds, KeyPair } from "../Types"
import { curveSign, hmacSign, curveVerify, encodeInt, generateCurveKeyPair, generateRegistrationId, signedKeyPair } from './generics' import { Curve, hmacSign, signedKeyPair } from './crypto'
import { encodeInt, generateRegistrationId } from './generics'
import { BinaryNode, S_WHATSAPP_NET, jidDecode, Binary } from '../WABinary' import { BinaryNode, S_WHATSAPP_NET, jidDecode, Binary } from '../WABinary'
import { createSignalIdentity } from './signal' import { createSignalIdentity } from './signal'
@@ -116,10 +117,10 @@ export const initInMemoryKeyStore = (
} }
export const initAuthState = (): AuthenticationState => { export const initAuthState = (): AuthenticationState => {
const identityKey = generateCurveKeyPair() const identityKey = Curve.generateKeyPair()
return { return {
creds: { creds: {
noiseKey: generateCurveKeyPair(), noiseKey: Curve.generateKeyPair(),
signedIdentityKey: identityKey, signedIdentityKey: identityKey,
signedPreKey: signedKeyPair(identityKey, 1), signedPreKey: signedKeyPair(identityKey, 1),
registrationId: generateRegistrationId(), registrationId: generateRegistrationId(),
@@ -158,12 +159,12 @@ export const configureSuccessfulPairing = (
const { accountSignatureKey, accountSignature } = account const { accountSignatureKey, accountSignature } = account
const accountMsg = Binary.build(new Uint8Array([6, 0]), account.details, signedIdentityKey.public).readByteArray() const accountMsg = Binary.build(new Uint8Array([6, 0]), account.details, signedIdentityKey.public).readByteArray()
if (!curveVerify(accountSignatureKey, accountMsg, accountSignature)) { if (!Curve.verify(accountSignatureKey, accountMsg, accountSignature)) {
throw new Boom('Failed to verify account signature') throw new Boom('Failed to verify account signature')
} }
const deviceMsg = Binary.build(new Uint8Array([6, 1]), account.details, signedIdentityKey.public, account.accountSignatureKey).readByteArray() const deviceMsg = Binary.build(new Uint8Array([6, 1]), account.details, signedIdentityKey.public, account.accountSignatureKey).readByteArray()
account.deviceSignature = curveSign(signedIdentityKey.private, deviceMsg) account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg)
const identity = createSignalIdentity(jid, accountSignatureKey) const identity = createSignalIdentity(jid, accountSignatureKey)