Encrypt device name on account create, on first launch if needed
This commit is contained in:
parent
775e31c854
commit
47f834cf5c
10 changed files with 282 additions and 95 deletions
|
@ -1,5 +1,5 @@
|
|||
/* eslint-env browser */
|
||||
/* global dcodeIO */
|
||||
/* global dcodeIO, libsignal */
|
||||
|
||||
/* eslint-disable camelcase, no-bitwise */
|
||||
|
||||
|
@ -10,9 +10,11 @@ module.exports = {
|
|||
concatenateBytes,
|
||||
constantTimeEqual,
|
||||
decryptAesCtr,
|
||||
decryptDeviceName,
|
||||
decryptSymmetric,
|
||||
deriveAccessKey,
|
||||
encryptAesCtr,
|
||||
encryptDeviceName,
|
||||
encryptSymmetric,
|
||||
fromEncodedBinaryToArrayBuffer,
|
||||
getAccessKeyVerifier,
|
||||
|
@ -30,6 +32,55 @@ module.exports = {
|
|||
|
||||
// High-level Operations
|
||||
|
||||
async function encryptDeviceName(deviceName, identityPublic) {
|
||||
const plaintext = bytesFromString(deviceName);
|
||||
const ephemeralKeyPair = await libsignal.KeyHelper.generateIdentityKeyPair();
|
||||
const masterSecret = await libsignal.Curve.async.calculateAgreement(
|
||||
identityPublic,
|
||||
ephemeralKeyPair.privKey
|
||||
);
|
||||
|
||||
const key1 = await hmacSha256(masterSecret, bytesFromString('auth'));
|
||||
const syntheticIv = _getFirstBytes(await hmacSha256(key1, plaintext), 16);
|
||||
|
||||
const key2 = await hmacSha256(masterSecret, bytesFromString('cipher'));
|
||||
const cipherKey = await hmacSha256(key2, syntheticIv);
|
||||
|
||||
const counter = getZeroes(16);
|
||||
const ciphertext = await encryptAesCtr(cipherKey, plaintext, counter);
|
||||
|
||||
return {
|
||||
ephemeralPublic: ephemeralKeyPair.pubKey,
|
||||
syntheticIv,
|
||||
ciphertext,
|
||||
};
|
||||
}
|
||||
|
||||
async function decryptDeviceName(
|
||||
{ ephemeralPublic, syntheticIv, ciphertext } = {},
|
||||
identityPrivate
|
||||
) {
|
||||
const masterSecret = await libsignal.Curve.async.calculateAgreement(
|
||||
ephemeralPublic,
|
||||
identityPrivate
|
||||
);
|
||||
|
||||
const key2 = await hmacSha256(masterSecret, bytesFromString('cipher'));
|
||||
const cipherKey = await hmacSha256(key2, syntheticIv);
|
||||
|
||||
const counter = getZeroes(16);
|
||||
const plaintext = await decryptAesCtr(cipherKey, ciphertext, counter);
|
||||
|
||||
const key1 = await hmacSha256(masterSecret, bytesFromString('auth'));
|
||||
const ourSyntheticIv = _getFirstBytes(await hmacSha256(key1, plaintext), 16);
|
||||
|
||||
if (!constantTimeEqual(ourSyntheticIv, syntheticIv)) {
|
||||
throw new Error('decryptDeviceName: synthetic IV did not match');
|
||||
}
|
||||
|
||||
return stringFromBytes(plaintext);
|
||||
}
|
||||
|
||||
async function deriveAccessKey(profileKey) {
|
||||
const iv = getZeroes(12);
|
||||
const plaintext = getZeroes(16);
|
||||
|
|
|
@ -325,6 +325,7 @@ function HTTPError(message, providedCode, response, stack) {
|
|||
|
||||
const URL_CALLS = {
|
||||
accounts: 'v1/accounts',
|
||||
updateDeviceName: 'v1/accounts/name',
|
||||
attachment: 'v1/attachments',
|
||||
deliveryCert: 'v1/certificate/delivery',
|
||||
supportUnauthenticatedDelivery: 'v1/devices/unauthenticated_delivery',
|
||||
|
@ -386,6 +387,7 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
sendMessages,
|
||||
sendMessagesUnauth,
|
||||
setSignedPreKey,
|
||||
updateDeviceName,
|
||||
};
|
||||
|
||||
function _ajax(param) {
|
||||
|
@ -568,6 +570,16 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
return response;
|
||||
}
|
||||
|
||||
function updateDeviceName(deviceName) {
|
||||
return _ajax({
|
||||
call: 'updateDeviceName',
|
||||
httpType: 'PUT',
|
||||
jsonData: {
|
||||
deviceName,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getDevices() {
|
||||
return _ajax({
|
||||
call: 'devices',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue