mirror of
https://github.com/signalapp/libsignal.git
synced 2026-05-10 00:52:18 +02:00
SealedSessionCipher encrypt
This commit is contained in:
@@ -136,6 +136,8 @@ public final class Native {
|
||||
|
||||
public static native boolean ScannableFingerprint_Compare(byte[] fprint1, byte[] fprint2);
|
||||
|
||||
public static native byte[] SealedSessionCipher_Encrypt(long destination, long senderCert, byte[] ptext, SessionStore sessionStore, IdentityKeyStore identityStore);
|
||||
|
||||
public static native long SenderCertificate_Deserialize(byte[] data);
|
||||
public static native void SenderCertificate_Destroy(long handle);
|
||||
public static native byte[] SenderCertificate_GetCertificate(long handle);
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.whispersystems.libsignal.state.SignalProtocolStore;
|
||||
import org.whispersystems.libsignal.util.ByteUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import org.signal.client.internal.Native;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -67,21 +69,12 @@ public class SealedSessionCipher {
|
||||
public byte[] encrypt(SignalProtocolAddress destinationAddress, SenderCertificate senderCertificate, byte[] paddedPlaintext)
|
||||
throws InvalidKeyException, UntrustedIdentityException
|
||||
{
|
||||
CiphertextMessage message = new SessionCipher(signalProtocolStore, destinationAddress).encrypt(paddedPlaintext);
|
||||
IdentityKeyPair ourIdentity = signalProtocolStore.getIdentityKeyPair();
|
||||
ECPublicKey theirIdentity = signalProtocolStore.getIdentity(destinationAddress).getPublicKey();
|
||||
|
||||
ECKeyPair ephemeral = Curve.generateKeyPair();
|
||||
byte[] ephemeralSalt = ByteUtil.combine("UnidentifiedDelivery".getBytes(), theirIdentity.serialize(), ephemeral.getPublicKey().serialize());
|
||||
EphemeralKeys ephemeralKeys = calculateEphemeralKeys(theirIdentity, ephemeral.getPrivateKey(), ephemeralSalt);
|
||||
byte[] staticKeyCiphertext = encrypt(ephemeralKeys.cipherKey, ephemeralKeys.macKey, ourIdentity.getPublicKey().getPublicKey().serialize());
|
||||
|
||||
byte[] staticSalt = ByteUtil.combine(ephemeralKeys.chainKey, staticKeyCiphertext);
|
||||
StaticKeys staticKeys = calculateStaticKeys(theirIdentity, ourIdentity.getPrivateKey(), staticSalt);
|
||||
UnidentifiedSenderMessageContent content = new UnidentifiedSenderMessageContent(message.getType(), senderCertificate, message.serialize());
|
||||
byte[] messageBytes = encrypt(staticKeys.cipherKey, staticKeys.macKey, content.getSerialized());
|
||||
|
||||
return new UnidentifiedSenderMessage(ephemeral.getPublicKey(), staticKeyCiphertext, messageBytes).getSerialized();
|
||||
return Native.SealedSessionCipher_Encrypt(
|
||||
destinationAddress.nativeHandle(),
|
||||
senderCertificate.nativeHandle(),
|
||||
paddedPlaintext,
|
||||
this.signalProtocolStore,
|
||||
this.signalProtocolStore);
|
||||
}
|
||||
|
||||
public DecryptionResult decrypt(CertificateValidator validator, byte[] ciphertext, long timestamp)
|
||||
@@ -159,7 +152,7 @@ public class SealedSessionCipher {
|
||||
private EphemeralKeys calculateEphemeralKeys(ECPublicKey ephemeralPublic, ECPrivateKey ephemeralPrivate, byte[] salt) throws InvalidKeyException {
|
||||
try {
|
||||
byte[] ephemeralSecret = Curve.calculateAgreement(ephemeralPublic, ephemeralPrivate);
|
||||
byte[] ephemeralDerived = new HKDFv3().deriveSecrets(ephemeralSecret, salt, new byte[0], 96);
|
||||
byte[] ephemeralDerived = new HKDFv3().deriveSecrets(ephemeralSecret, salt, null, 96);
|
||||
byte[][] ephemeralDerivedParts = ByteUtil.split(ephemeralDerived, 32, 32, 32);
|
||||
|
||||
return new EphemeralKeys(ephemeralDerivedParts[0], ephemeralDerivedParts[1], ephemeralDerivedParts[2]);
|
||||
@@ -171,7 +164,7 @@ public class SealedSessionCipher {
|
||||
private StaticKeys calculateStaticKeys(ECPublicKey staticPublic, ECPrivateKey staticPrivate, byte[] salt) throws InvalidKeyException {
|
||||
try {
|
||||
byte[] staticSecret = Curve.calculateAgreement(staticPublic, staticPrivate);
|
||||
byte[] staticDerived = new HKDFv3().deriveSecrets(staticSecret, salt, new byte[0], 96);
|
||||
byte[] staticDerived = new HKDFv3().deriveSecrets(staticSecret, salt, null, 96);
|
||||
byte[][] staticDerivedParts = ByteUtil.split(staticDerived, 32, 32, 32);
|
||||
|
||||
return new StaticKeys(staticDerivedParts[1], staticDerivedParts[2]);
|
||||
@@ -192,24 +185,6 @@ public class SealedSessionCipher {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] encrypt(SecretKeySpec cipherKey, SecretKeySpec macKey, byte[] plaintext) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, cipherKey, new IvParameterSpec(new byte[16]));
|
||||
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(macKey);
|
||||
|
||||
byte[] ciphertext = cipher.doFinal(plaintext);
|
||||
byte[] ourFullMac = mac.doFinal(ciphertext);
|
||||
byte[] ourMac = ByteUtil.trim(ourFullMac, 10);
|
||||
|
||||
return ByteUtil.combine(ciphertext, ourMac);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | java.security.InvalidKeyException | BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] decrypt(SecretKeySpec cipherKey, SecretKeySpec macKey, byte[] ciphertext) throws InvalidMacException {
|
||||
try {
|
||||
if (ciphertext.length < 10) {
|
||||
|
||||
Reference in New Issue
Block a user