fix: Migrate Double Ratchet to the helper functions
This commit is contained in:
parent
4d6dbef549
commit
31d3897995
@ -1,62 +1,24 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'package:cryptography/cryptography.dart';
|
|
||||||
import 'package:omemo_dart/protobuf/schema.pb.dart';
|
import 'package:omemo_dart/protobuf/schema.pb.dart';
|
||||||
|
import 'package:omemo_dart/src/crypto.dart';
|
||||||
import 'package:omemo_dart/src/errors.dart';
|
import 'package:omemo_dart/src/errors.dart';
|
||||||
import 'package:omemo_dart/src/helpers.dart';
|
import 'package:omemo_dart/src/helpers.dart';
|
||||||
|
|
||||||
/// Info string for ENCRYPT
|
/// Info string for ENCRYPT
|
||||||
const encryptHkdfInfoString = 'OMEMO Message Key Material';
|
const encryptHkdfInfoString = 'OMEMO Message Key Material';
|
||||||
|
|
||||||
/// cryptography _really_ wants to check the MAC output from AES-256-CBC. Since
|
|
||||||
/// we don't have it, we need the MAC check to always "pass".
|
|
||||||
class NoMacSecretBox extends SecretBox {
|
|
||||||
NoMacSecretBox(super.cipherText, { required super.nonce }) : super(mac: Mac.empty);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> checkMac({
|
|
||||||
required MacAlgorithm macAlgorithm,
|
|
||||||
required SecretKey secretKey,
|
|
||||||
required List<int> aad,
|
|
||||||
}) async {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Signals ENCRYPT function as specified by OMEMO 0.8.3.
|
/// Signals ENCRYPT function as specified by OMEMO 0.8.3.
|
||||||
/// Encrypt [plaintext] using the message key [mk], given associated_data [associatedData]
|
/// Encrypt [plaintext] using the message key [mk], given associated_data [associatedData]
|
||||||
/// and the AD output from the X3DH [sessionAd].
|
/// and the AD output from the X3DH [sessionAd].
|
||||||
Future<List<int>> encrypt(List<int> mk, List<int> plaintext, List<int> associatedData, List<int> sessionAd) async {
|
Future<List<int>> encrypt(List<int> mk, List<int> plaintext, List<int> associatedData, List<int> sessionAd) async {
|
||||||
final hkdf = Hkdf(
|
// Generate encryption, authentication key and IV
|
||||||
hmac: Hmac(Sha256()),
|
final keys = await deriveEncryptionKeys(mk, encryptHkdfInfoString);
|
||||||
outputLength: 80,
|
final ciphertext = await aes256CbcEncrypt(plaintext, keys.encryptionKey, keys.iv);
|
||||||
);
|
|
||||||
final hkdfResult = await hkdf.deriveKey(
|
|
||||||
secretKey: SecretKey(mk),
|
|
||||||
nonce: List<int>.filled(32, 0x0),
|
|
||||||
info: utf8.encode(encryptHkdfInfoString),
|
|
||||||
);
|
|
||||||
final hkdfBytes = await hkdfResult.extractBytes();
|
|
||||||
|
|
||||||
// Split hkdfBytes into encryption, authentication key and IV
|
|
||||||
final encryptionKey = hkdfBytes.sublist(0, 32);
|
|
||||||
final authenticationKey = hkdfBytes.sublist(32, 64);
|
|
||||||
final iv = hkdfBytes.sublist(64, 80);
|
|
||||||
|
|
||||||
final aesResult = await AesCbc.with256bits(
|
|
||||||
macAlgorithm: MacAlgorithm.empty,
|
|
||||||
).encrypt(
|
|
||||||
plaintext,
|
|
||||||
secretKey: SecretKey(encryptionKey),
|
|
||||||
nonce: iv,
|
|
||||||
);
|
|
||||||
|
|
||||||
final header = OMEMOMessage.fromBuffer(associatedData.sublist(sessionAd.length))
|
final header = OMEMOMessage.fromBuffer(associatedData.sublist(sessionAd.length))
|
||||||
..ciphertext = aesResult.cipherText;
|
..ciphertext = ciphertext;
|
||||||
final headerBytes = header.writeToBuffer();
|
final headerBytes = header.writeToBuffer();
|
||||||
final hmacInput = concat([sessionAd, headerBytes]);
|
final hmacInput = concat([sessionAd, headerBytes]);
|
||||||
final hmacResult = (await Hmac.sha256().calculateMac(
|
final hmacResult = await truncatedHmac(hmacInput, keys.authenticationKey);
|
||||||
hmacInput,
|
|
||||||
secretKey: SecretKey(authenticationKey),
|
|
||||||
)).bytes.sublist(0, 16);
|
|
||||||
|
|
||||||
final message = OMEMOAuthenticatedMessage()
|
final message = OMEMOAuthenticatedMessage()
|
||||||
..mac = hmacResult
|
..mac = hmacResult
|
||||||
..message = headerBytes;
|
..message = headerBytes;
|
||||||
@ -67,46 +29,19 @@ Future<List<int>> encrypt(List<int> mk, List<int> plaintext, List<int> associate
|
|||||||
/// Decrypt [ciphertext] with the message key [mk], given the associated_data [associatedData]
|
/// Decrypt [ciphertext] with the message key [mk], given the associated_data [associatedData]
|
||||||
/// and the AD output from the X3DH.
|
/// and the AD output from the X3DH.
|
||||||
Future<List<int>> decrypt(List<int> mk, List<int> ciphertext, List<int> associatedData, List<int> sessionAd) async {
|
Future<List<int>> decrypt(List<int> mk, List<int> ciphertext, List<int> associatedData, List<int> sessionAd) async {
|
||||||
// Generate the keys and iv from mk
|
// Generate encryption, authentication key and IV
|
||||||
final hkdf = Hkdf(
|
final keys = await deriveEncryptionKeys(mk, encryptHkdfInfoString);
|
||||||
hmac: Hmac(Sha256()),
|
|
||||||
outputLength: 80,
|
|
||||||
);
|
|
||||||
final hkdfResult = await hkdf.deriveKey(
|
|
||||||
secretKey: SecretKey(mk),
|
|
||||||
nonce: List<int>.filled(32, 0x0),
|
|
||||||
info: utf8.encode(encryptHkdfInfoString),
|
|
||||||
);
|
|
||||||
final hkdfBytes = await hkdfResult.extractBytes();
|
|
||||||
|
|
||||||
// Split hkdfBytes into encryption, authentication key and IV
|
|
||||||
final encryptionKey = hkdfBytes.sublist(0, 32);
|
|
||||||
final authenticationKey = hkdfBytes.sublist(32, 64);
|
|
||||||
final iv = hkdfBytes.sublist(64, 80);
|
|
||||||
|
|
||||||
// Assumption ciphertext is a OMEMOAuthenticatedMessage
|
// Assumption ciphertext is a OMEMOAuthenticatedMessage
|
||||||
final message = OMEMOAuthenticatedMessage.fromBuffer(ciphertext);
|
final message = OMEMOAuthenticatedMessage.fromBuffer(ciphertext);
|
||||||
final header = OMEMOMessage.fromBuffer(message.message);
|
final header = OMEMOMessage.fromBuffer(message.message);
|
||||||
|
|
||||||
final hmacInput = concat([sessionAd, header.writeToBuffer()]);
|
final hmacInput = concat([sessionAd, header.writeToBuffer()]);
|
||||||
final hmacResult = (await Hmac.sha256().calculateMac(
|
final hmacResult = await truncatedHmac(hmacInput, keys.authenticationKey);
|
||||||
hmacInput,
|
|
||||||
secretKey: SecretKey(authenticationKey),
|
|
||||||
)).bytes.sublist(0, 16);
|
|
||||||
|
|
||||||
if (!listsEqual(hmacResult, message.mac)) {
|
if (!listsEqual(hmacResult, message.mac)) {
|
||||||
throw InvalidMessageHMACException();
|
throw InvalidMessageHMACException();
|
||||||
}
|
}
|
||||||
|
|
||||||
final plaintext = await AesCbc.with256bits(
|
|
||||||
macAlgorithm: MacAlgorithm.empty,
|
|
||||||
).decrypt(
|
|
||||||
NoMacSecretBox(
|
|
||||||
header.ciphertext,
|
|
||||||
nonce: iv,
|
|
||||||
),
|
|
||||||
secretKey: SecretKey(encryptionKey),
|
|
||||||
);
|
|
||||||
|
|
||||||
return plaintext;
|
return aes256CbcDecrypt(header.ciphertext, keys.encryptionKey, keys.iv);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user