org.whispersystems.libsignal.util.ByteUtil Java Examples

The following examples show how to use org.whispersystems.libsignal.util.ByteUtil. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ProfileCipher.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
public byte[] encryptName(byte[] input, int paddedLength) {
  try {
    byte[] inputPadded = new byte[paddedLength];

    if (input.length > inputPadded.length) {
      throw new IllegalArgumentException("Input is too long: " + new String(input));
    }

    System.arraycopy(input, 0, inputPadded, 0, input.length);

    byte[] nonce = Util.getSecretBytes(12);

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.serialize(), "AES"), new GCMParameterSpec(128, nonce));

    return ByteUtil.combine(nonce, cipher.doFinal(inputPadded));
  } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | BadPaddingException | NoSuchPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
    throw new AssertionError(e);
  }
}
 
Example #2
Source File: NumericFingerprintGenerator.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
private byte[] getFingerprint(int iterations, byte[] stableIdentifier, List<IdentityKey> unsortedIdentityKeys) {
  try {
    MessageDigest digest    = MessageDigest.getInstance("SHA-512");
    byte[]        publicKey = getLogicalKeyBytes(unsortedIdentityKeys);
    byte[]        hash      = ByteUtil.combine(ByteUtil.shortToByteArray(FINGERPRINT_VERSION),
                                               publicKey, stableIdentifier);

    for (int i=0;i<iterations;i++) {
      digest.update(hash);
      hash = digest.digest(publicKey);
    }

    return hash;
  } catch (NoSuchAlgorithmException e) {
    throw new AssertionError(e);
  }
}
 
Example #3
Source File: ScannableFingerprint.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
ScannableFingerprint(int version, byte[] localFingerprintData, byte[] remoteFingerprintData)
{
  LogicalFingerprint localFingerprint = LogicalFingerprint.newBuilder()
                                                          .setContent(ByteString.copyFrom(ByteUtil.trim(localFingerprintData, 32)))
                                                          .build();

  LogicalFingerprint remoteFingerprint = LogicalFingerprint.newBuilder()
                                                           .setContent(ByteString.copyFrom(ByteUtil.trim(remoteFingerprintData, 32)))
                                                           .build();

  this.version      = version;
  this.fingerprints = CombinedFingerprints.newBuilder()
                                          .setVersion(version)
                                          .setLocalFingerprint(localFingerprint)
                                          .setRemoteFingerprint(remoteFingerprint)
                                          .build();
}
 
Example #4
Source File: ContactDiscoveryCipher.java    From libsignal-service-java with GNU General Public License v3.0 6 votes vote down vote up
public DiscoveryRequest createDiscoveryRequest(List<String> addressBook, RemoteAttestation remoteAttestation) {
  try {
    ByteArrayOutputStream requestDataStream = new ByteArrayOutputStream();

    for (String address : addressBook) {
      requestDataStream.write(ByteUtil.longToByteArray(Long.parseLong(address)));
    }

    byte[]         requestData = requestDataStream.toByteArray();
    byte[]         nonce       = Util.getSecretBytes(12);
    Cipher         cipher      = Cipher.getInstance("AES/GCM/NoPadding");

    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(remoteAttestation.getKeys().getClientKey(), "AES"), new GCMParameterSpec(TAG_LENGTH_BITS, nonce));
    cipher.updateAAD(remoteAttestation.getRequestId());

    byte[]   cipherText = cipher.doFinal(requestData);
    byte[][] parts      = ByteUtil.split(cipherText, cipherText.length - TAG_LENGTH_BYTES, TAG_LENGTH_BYTES);

    return new DiscoveryRequest(addressBook.size(), remoteAttestation.getRequestId(), nonce, parts[0], parts[1]);
  } catch (IOException | NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
    throw new AssertionError(e);
  }
}
 
Example #5
Source File: ProfileCipher.java    From libsignal-service-java with GNU General Public License v3.0 6 votes vote down vote up
public byte[] encryptName(byte[] input, int paddedLength) {
  try {
    byte[] inputPadded = new byte[paddedLength];

    if (input.length > inputPadded.length) {
      throw new IllegalArgumentException("Input is too long: " + new String(input));
    }

    System.arraycopy(input, 0, inputPadded, 0, input.length);

    byte[] nonce = Util.getSecretBytes(12);

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, nonce));

    return ByteUtil.combine(nonce, cipher.doFinal(inputPadded));
  } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | BadPaddingException | NoSuchPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
    throw new AssertionError(e);
  }
}
 
Example #6
Source File: SenderKeyMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
public SenderKeyMessage(int keyId, int iteration, byte[] ciphertext, ECPrivateKey signatureKey) {
  byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
  byte[] message = SignalProtos.SenderKeyMessage.newBuilder()
                                                .setId(keyId)
                                                .setIteration(iteration)
                                                .setCiphertext(ByteString.copyFrom(ciphertext))
                                                .build().toByteArray();

  byte[] signature = getSignature(signatureKey, ByteUtil.combine(version, message));

  this.serialized       = ByteUtil.combine(version, message, signature);
  this.messageVersion   = CURRENT_VERSION;
  this.keyId            = keyId;
  this.iteration        = iteration;
  this.ciphertext       = ciphertext;
}
 
Example #7
Source File: ProfileCipher.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
public byte[] encryptName(byte[] input, int paddedLength) {
    try {
        byte[] inputPadded = new byte[paddedLength];

        if (input.length > inputPadded.length) {
            throw new IllegalArgumentException("Input is too long: " + new String(input));
        }

        System.arraycopy(input, 0, inputPadded, 0, input.length);

        byte[] nonce = Util.getSecretBytes(12);

        GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
        cipher.init(true, new AEADParameters(new KeyParameter(key), 128, nonce));

        byte[] ciphertext = new byte[cipher.getUpdateOutputSize(inputPadded.length)];
        cipher.processBytes(inputPadded, 0, inputPadded.length, ciphertext, 0);

        byte[] tag = new byte[cipher.getOutputSize(0)];
        cipher.doFinal(tag, 0);

        return ByteUtil.combine(nonce, ciphertext, tag);
    } catch (InvalidCipherTextException e) {
        throw new AssertionError(e);
    }
}
 
Example #8
Source File: SignalMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
public SignalMessage(int messageVersion, SecretKeySpec macKey, ECPublicKey senderRatchetKey,
                     int counter, int previousCounter, byte[] ciphertext,
                     IdentityKey senderIdentityKey,
                     IdentityKey receiverIdentityKey)
{
  byte[] version = {ByteUtil.intsToByteHighAndLow(messageVersion, CURRENT_VERSION)};
  byte[] message = SignalProtos.SignalMessage.newBuilder()
                                             .setRatchetKey(ByteString.copyFrom(senderRatchetKey.serialize()))
                                             .setCounter(counter)
                                             .setPreviousCounter(previousCounter)
                                             .setCiphertext(ByteString.copyFrom(ciphertext))
                                             .build().toByteArray();

  byte[] mac     = getMac(senderIdentityKey, receiverIdentityKey, macKey, ByteUtil.combine(version, message));

  this.serialized       = ByteUtil.combine(version, message, mac);
  this.senderRatchetKey = senderRatchetKey;
  this.counter          = counter;
  this.previousCounter  = previousCounter;
  this.ciphertext       = ciphertext;
  this.messageVersion   = messageVersion;
}
 
Example #9
Source File: FullBackupBase.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
static @NonNull byte[] getBackupKey(@NonNull String passphrase, @Nullable byte[] salt) {
  try {
    EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, 0));

    MessageDigest digest = MessageDigest.getInstance("SHA-512");
    byte[]        input  = passphrase.replace(" ", "").getBytes();
    byte[]        hash   = input;

    if (salt != null) digest.update(salt);

    for (int i=0;i<250000;i++) {
      if (i % 1000 == 0) EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, 0));
      digest.update(hash);
      hash = digest.digest(input);
    }

    return ByteUtil.trim(hash, 32);
  } catch (NoSuchAlgorithmException e) {
    throw new AssertionError(e);
  }
}
 
Example #10
Source File: SignalMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
private byte[] getMac(IdentityKey senderIdentityKey,
                      IdentityKey receiverIdentityKey,
                      SecretKeySpec macKey, byte[] serialized)
{
  try {
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(macKey);

    mac.update(senderIdentityKey.getPublicKey().serialize());
    mac.update(receiverIdentityKey.getPublicKey().serialize());

    byte[] fullMac = mac.doFinal(serialized);
    return ByteUtil.trim(fullMac, MAC_LENGTH);
  } catch (NoSuchAlgorithmException | java.security.InvalidKeyException e) {
    throw new AssertionError(e);
  }
}
 
Example #11
Source File: DeviceConsistencyCommitment.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
public DeviceConsistencyCommitment(int generation, List<IdentityKey> identityKeys) {
  try {
    ArrayList<IdentityKey> sortedIdentityKeys = new ArrayList<>(identityKeys);
    Collections.sort(sortedIdentityKeys, new IdentityKeyComparator());

    MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
    messageDigest.update(VERSION.getBytes());
    messageDigest.update(ByteUtil.intToByteArray(generation));

    for (IdentityKey commitment : sortedIdentityKeys) {
      messageDigest.update(commitment.getPublicKey().serialize());
    }

    this.generation = generation;
    this.serialized = messageDigest.digest();
  } catch (NoSuchAlgorithmException e) {
    throw new AssertionError(e);
  }
}
 
Example #12
Source File: DeviceConsistencyCodeGenerator.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
public static String generateFor(DeviceConsistencyCommitment commitment,
                                 List<DeviceConsistencySignature> signatures)
{
  try {
    ArrayList<DeviceConsistencySignature> sortedSignatures = new ArrayList<>(signatures);
    Collections.sort(sortedSignatures, new SignatureComparator());

    MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
    messageDigest.update(ByteUtil.shortToByteArray(CODE_VERSION));
    messageDigest.update(commitment.toByteArray());

    for (DeviceConsistencySignature signature : sortedSignatures) {
      messageDigest.update(signature.getVrfOutput());
    }

    byte[] hash = messageDigest.digest();

    String digits = getEncodedChunk(hash, 0) + getEncodedChunk(hash, 5);
    return digits.substring(0, 6);

  } catch (NoSuchAlgorithmException e) {
    throw new AssertionError(e);
  }
}
 
Example #13
Source File: AESCipher.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
static AESEncryptedResult encrypt(byte[] key, byte[] aad, byte[] requestData) {
  try {
    byte[] iv     = Util.getSecretBytes(12);
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(TAG_LENGTH_BITS, iv));
    cipher.updateAAD(aad);

    byte[]   cipherText = cipher.doFinal(requestData);
    byte[][] parts      = ByteUtil.split(cipherText, cipherText.length - TAG_LENGTH_BYTES, TAG_LENGTH_BYTES);

    byte[] mac  = parts[1];
    byte[] data = parts[0];

    return new AESEncryptedResult(iv, data, mac, aad);
  } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
    throw new AssertionError(e);
  }
}
 
Example #14
Source File: ContactDiscoveryCipher.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
public static DiscoveryRequest createDiscoveryRequest(List<String> addressBook, RemoteAttestation remoteAttestation) {
  try {
    ByteArrayOutputStream requestDataStream = new ByteArrayOutputStream();

    for (String address : addressBook) {
      requestDataStream.write(ByteUtil.longToByteArray(Long.parseLong(address)));
    }

    byte[] clientKey   = remoteAttestation.getKeys().getClientKey();
    byte[] requestData = requestDataStream.toByteArray();
    byte[] aad         = remoteAttestation.getRequestId();

    AESCipher.AESEncryptedResult aesEncryptedResult = AESCipher.encrypt(clientKey, aad, requestData);

    return new DiscoveryRequest(addressBook.size(), aesEncryptedResult.aad, aesEncryptedResult.iv, aesEncryptedResult.data, aesEncryptedResult.mac);
  } catch (IOException e) {
    throw new AssertionError(e);
  }
}
 
Example #15
Source File: SignalMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public void verifyMac(IdentityKey senderIdentityKey, IdentityKey receiverIdentityKey, SecretKeySpec macKey)
    throws InvalidMessageException
{
  byte[][] parts    = ByteUtil.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH);
  byte[]   ourMac   = getMac(senderIdentityKey, receiverIdentityKey, macKey, parts[0]);
  byte[]   theirMac = parts[1];

  if (!MessageDigest.isEqual(ourMac, theirMac)) {
    throw new InvalidMessageException("Bad Mac!");
  }
}
 
Example #16
Source File: DerivedMessageSecrets.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public DerivedMessageSecrets(byte[] okm) {
  try {
    byte[][] keys = ByteUtil.split(okm, CIPHER_KEY_LENGTH, MAC_KEY_LENGTH, IV_LENGTH);

    this.cipherKey = new SecretKeySpec(keys[0], "AES");
    this.macKey    = new SecretKeySpec(keys[1], "HmacSHA256");
    this.iv        = new IvParameterSpec(keys[2]);
  } catch (ParseException e) {
    throw new AssertionError(e);
  }
}
 
Example #17
Source File: SignalMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public SignalMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException {
  try {
    byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH);
    byte     version      = messageParts[0][0];
    byte[]   message      = messageParts[1];
    byte[]   mac          = messageParts[2];

    if (ByteUtil.highBitsToInt(version) < CURRENT_VERSION) {
      throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
    }

    if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
      throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
    }

    SignalProtos.SignalMessage whisperMessage = SignalProtos.SignalMessage.parseFrom(message);

    if (!whisperMessage.hasCiphertext() ||
        !whisperMessage.hasCounter() ||
        !whisperMessage.hasRatchetKey())
    {
      throw new InvalidMessageException("Incomplete message.");
    }

    this.serialized       = serialized;
    this.senderRatchetKey = Curve.decodePoint(whisperMessage.getRatchetKey().toByteArray(), 0);
    this.messageVersion   = ByteUtil.highBitsToInt(version);
    this.counter          = whisperMessage.getCounter();
    this.previousCounter  = whisperMessage.getPreviousCounter();
    this.ciphertext       = whisperMessage.getCiphertext().toByteArray();
  } catch (InvalidProtocolBufferException | InvalidKeyException | ParseException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #18
Source File: SenderKeyMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public void verifySignature(ECPublicKey signatureKey)
    throws InvalidMessageException
{
  try {
    byte[][] parts    = ByteUtil.split(serialized, serialized.length - SIGNATURE_LENGTH, SIGNATURE_LENGTH);

    if (!Curve.verifySignature(signatureKey, parts[0], parts[1])) {
      throw new InvalidMessageException("Invalid signature!");
    }

  } catch (InvalidKeyException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #19
Source File: SenderKeyMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public SenderKeyMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException {
  try {
    byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - SIGNATURE_LENGTH, SIGNATURE_LENGTH);
    byte     version      = messageParts[0][0];
    byte[]   message      = messageParts[1];
    byte[]   signature    = messageParts[2];

    if (ByteUtil.highBitsToInt(version) < 3) {
      throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
    }

    if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
      throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
    }

    SignalProtos.SenderKeyMessage senderKeyMessage = SignalProtos.SenderKeyMessage.parseFrom(message);

    if (!senderKeyMessage.hasId() ||
        !senderKeyMessage.hasIteration() ||
        !senderKeyMessage.hasCiphertext())
    {
      throw new InvalidMessageException("Incomplete message.");
    }

    this.serialized     = serialized;
    this.messageVersion = ByteUtil.highBitsToInt(version);
    this.keyId          = senderKeyMessage.getId();
    this.iteration      = senderKeyMessage.getIteration();
    this.ciphertext     = senderKeyMessage.getCiphertext().toByteArray();
  } catch (InvalidProtocolBufferException | ParseException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #20
Source File: UnidentifiedAccess.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
public static byte[] deriveAccessKeyFrom(ProfileKey profileKey) {
  try {
    byte[]         nonce  = new byte[12];
    byte[]         input  = new byte[16];

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(profileKey.serialize(), "AES"), new GCMParameterSpec(128, nonce));

    byte[] ciphertext = cipher.doFinal(input);

    return ByteUtil.trim(ciphertext, 16);
  } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | BadPaddingException | IllegalBlockSizeException e) {
    throw new AssertionError(e);
  }
}
 
Example #21
Source File: PreKeySignalMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public PreKeySignalMessage(int messageVersion, int registrationId, Optional<Integer> preKeyId,
                           int signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey,
                           SignalMessage message)
{
  this.version        = messageVersion;
  this.registrationId = registrationId;
  this.preKeyId       = preKeyId;
  this.signedPreKeyId = signedPreKeyId;
  this.baseKey        = baseKey;
  this.identityKey    = identityKey;
  this.message        = message;

  SignalProtos.PreKeySignalMessage.Builder builder =
      SignalProtos.PreKeySignalMessage.newBuilder()
                                      .setSignedPreKeyId(signedPreKeyId)
                                      .setBaseKey(ByteString.copyFrom(baseKey.serialize()))
                                      .setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
                                      .setMessage(ByteString.copyFrom(message.serialize()))
                                      .setRegistrationId(registrationId);

  if (preKeyId.isPresent()) {
    builder.setPreKeyId(preKeyId.get());
  }

  byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(this.version, CURRENT_VERSION)};
  byte[] messageBytes = builder.build().toByteArray();

  this.serialized = ByteUtil.combine(versionBytes, messageBytes);
}
 
Example #22
Source File: PreKeySignalMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public PreKeySignalMessage(byte[] serialized)
    throws InvalidMessageException, InvalidVersionException
{
  try {
    this.version = ByteUtil.highBitsToInt(serialized[0]);

    if (this.version > CiphertextMessage.CURRENT_VERSION) {
      throw new InvalidVersionException("Unknown version: " + this.version);
    }

    if (this.version < CiphertextMessage.CURRENT_VERSION) {
      throw new LegacyMessageException("Legacy version: " + this.version);
    }

    SignalProtos.PreKeySignalMessage preKeyWhisperMessage
        = SignalProtos.PreKeySignalMessage.parseFrom(ByteString.copyFrom(serialized, 1,
                                                                         serialized.length-1));

    if (!preKeyWhisperMessage.hasSignedPreKeyId()  ||
        !preKeyWhisperMessage.hasBaseKey()         ||
        !preKeyWhisperMessage.hasIdentityKey()     ||
        !preKeyWhisperMessage.hasMessage())
    {
      throw new InvalidMessageException("Incomplete message.");
    }

    this.serialized     = serialized;
    this.registrationId = preKeyWhisperMessage.getRegistrationId();
    this.preKeyId       = preKeyWhisperMessage.hasPreKeyId() ? Optional.of(preKeyWhisperMessage.getPreKeyId()) : Optional.<Integer>absent();
    this.signedPreKeyId = preKeyWhisperMessage.hasSignedPreKeyId() ? preKeyWhisperMessage.getSignedPreKeyId() : -1;
    this.baseKey        = Curve.decodePoint(preKeyWhisperMessage.getBaseKey().toByteArray(), 0);
    this.identityKey    = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.getIdentityKey().toByteArray(), 0));
    this.message        = new SignalMessage(preKeyWhisperMessage.getMessage().toByteArray());
  } catch (InvalidProtocolBufferException | InvalidKeyException | LegacyMessageException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #23
Source File: SenderKeyDistributionMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public SenderKeyDistributionMessage(byte[] serialized) throws LegacyMessageException, InvalidMessageException {
  try {
    byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1);
    byte     version      = messageParts[0][0];
    byte[]   message      = messageParts[1];

    if (ByteUtil.highBitsToInt(version) < CiphertextMessage.CURRENT_VERSION) {
      throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
    }

    if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
      throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
    }

    SignalProtos.SenderKeyDistributionMessage distributionMessage = SignalProtos.SenderKeyDistributionMessage.parseFrom(message);

    if (!distributionMessage.hasId()        ||
        !distributionMessage.hasIteration() ||
        !distributionMessage.hasChainKey()  ||
        !distributionMessage.hasSigningKey())
    {
      throw new InvalidMessageException("Incomplete message.");
    }

    this.serialized   = serialized;
    this.id           = distributionMessage.getId();
    this.iteration    = distributionMessage.getIteration();
    this.chainKey     = distributionMessage.getChainKey().toByteArray();
    this.signatureKey = Curve.decodePoint(distributionMessage.getSigningKey().toByteArray(), 0);
  } catch (InvalidProtocolBufferException | InvalidKeyException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #24
Source File: SenderKeyDistributionMessage.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public SenderKeyDistributionMessage(int id, int iteration, byte[] chainKey, ECPublicKey signatureKey) {
  byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
  byte[] protobuf = SignalProtos.SenderKeyDistributionMessage.newBuilder()
                                                             .setId(id)
                                                             .setIteration(iteration)
                                                             .setChainKey(ByteString.copyFrom(chainKey))
                                                             .setSigningKey(ByteString.copyFrom(signatureKey.serialize()))
                                                             .build().toByteArray();

  this.id           = id;
  this.iteration    = iteration;
  this.chainKey     = chainKey;
  this.signatureKey = signatureKey;
  this.serialized   = ByteUtil.combine(version, protobuf);
}
 
Example #25
Source File: RatchetingSession.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
private static DerivedKeys calculateDerivedKeys(byte[] masterSecret) {
  HKDF     kdf                = new HKDFv3();
  byte[]   derivedSecretBytes = kdf.deriveSecrets(masterSecret, "WhisperText".getBytes(), 64);
  byte[][] derivedSecrets     = ByteUtil.split(derivedSecretBytes, 32, 32);

  return new DerivedKeys(new RootKey(kdf, derivedSecrets[0]),
                         new ChainKey(kdf, derivedSecrets[1], 0));
}
 
Example #26
Source File: FullBackupExporter.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
private BackupFrameOutputStream(@NonNull File output, @NonNull String passphrase) throws IOException {
  try {
    byte[]   salt    = Util.getSecretBytes(32);
    byte[]   key     = getBackupKey(passphrase, salt);
    byte[]   derived = new HKDFv3().deriveSecrets(key, "Backup Export".getBytes(), 64);
    byte[][] split   = ByteUtil.split(derived, 32, 32);

    this.cipherKey = split[0];
    this.macKey    = split[1];

    this.cipher       = Cipher.getInstance("AES/CTR/NoPadding");
    this.mac          = Mac.getInstance("HmacSHA256");
    this.outputStream = new FileOutputStream(output);
    this.iv           = Util.getSecretBytes(16);
    this.counter      = Conversions.byteArrayToInt(iv);

    mac.init(new SecretKeySpec(macKey, "HmacSHA256"));

    byte[] header = BackupProtos.BackupFrame.newBuilder().setHeader(BackupProtos.Header.newBuilder()
                                                                                       .setIv(ByteString.copyFrom(iv))
                                                                                       .setSalt(ByteString.copyFrom(salt)))
                                            .build().toByteArray();

    outputStream.write(Conversions.intToByteArray(header.length));
    outputStream.write(header);
  } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
    throw new AssertionError(e);
  }
}
 
Example #27
Source File: RemoteAttestationCipher.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
public static void verifyIasSignature(KeyStore trustStore, String certificates, String signatureBody, String signature, Quote quote)
    throws SignatureException
{
  if (certificates == null || certificates.isEmpty()) {
    throw new SignatureException("No certificates.");
  }

  try {
    SigningCertificate signingCertificate = new SigningCertificate(certificates, trustStore);
    signingCertificate.verifySignature(signatureBody, signature);

    SignatureBodyEntity signatureBodyEntity = JsonUtil.fromJson(signatureBody, SignatureBodyEntity.class);

    if (signatureBodyEntity.getVersion() != SIGNATURE_BODY_VERSION) {
      throw new SignatureException("Unexpected signed quote version " + signatureBodyEntity.getVersion());
    }

    if (!MessageDigest.isEqual(ByteUtil.trim(signatureBodyEntity.getIsvEnclaveQuoteBody(), 432), ByteUtil.trim(quote.getQuoteBytes(), 432))) {
      throw new SignatureException("Signed quote is not the same as RA quote: " + Hex.toStringCondensed(signatureBodyEntity.getIsvEnclaveQuoteBody()) + " vs " + Hex.toStringCondensed(quote.getQuoteBytes()));
    }

    if (!"OK".equals(signatureBodyEntity.getIsvEnclaveQuoteStatus())) {
      throw new SignatureException("Quote status is: " + signatureBodyEntity.getIsvEnclaveQuoteStatus());
    }

    if (Instant.from(ZonedDateTime.of(LocalDateTime.from(DateTimeFormatter.ofPattern("yyy-MM-dd'T'HH:mm:ss.SSSSSS").parse(signatureBodyEntity.getTimestamp())), ZoneId.of("UTC")))
               .plus(Period.ofDays(1))
               .isBefore(Instant.now()))
    {
      throw new SignatureException("Signature is expired");
    }

  } catch (CertificateException | CertPathValidatorException | IOException e) {
    throw new SignatureException(e);
  }
}
 
Example #28
Source File: RemoteAttestationKeys.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
public RemoteAttestationKeys(Curve25519KeyPair keyPair, byte[] serverPublicEphemeral, byte[] serverPublicStatic) {
  byte[] ephemeralToEphemeral = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicEphemeral, keyPair.getPrivateKey());
  byte[] ephemeralToStatic    = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicStatic, keyPair.getPrivateKey());

  byte[] masterSecret = ByteUtil.combine(ephemeralToEphemeral, ephemeralToStatic                          );
  byte[] publicKeys   = ByteUtil.combine(keyPair.getPublicKey(), serverPublicEphemeral, serverPublicStatic);

  HKDFv3 generator = new HKDFv3();
  byte[] keys      = generator.deriveSecrets(masterSecret, publicKeys, null, clientKey.length + serverKey.length);

  System.arraycopy(keys, 0, clientKey, 0, clientKey.length);
  System.arraycopy(keys, clientKey.length, serverKey, 0, serverKey.length);
}
 
Example #29
Source File: FullBackupImporter.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
private BackupFrame readFrame(InputStream in) throws IOException {
  try {
    byte[] length = new byte[4];
    Util.readFully(in, length);

    byte[] frame = new byte[Conversions.byteArrayToInt(length)];
    Util.readFully(in, frame);

    byte[] theirMac = new byte[10];
    System.arraycopy(frame, frame.length - 10, theirMac, 0, theirMac.length);

    mac.update(frame, 0, frame.length - 10);
    byte[] ourMac = ByteUtil.trim(mac.doFinal(), 10);

    if (!MessageDigest.isEqual(ourMac, theirMac)) {
      throw new IOException("Bad MAC");
    }

    Conversions.intToByteArray(iv, 0, counter++);
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv));

    byte[] plaintext = cipher.doFinal(frame, 0, frame.length - 10);

    return BackupFrame.parseFrom(plaintext);
  } catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
    throw new AssertionError(e);
  }
}
 
Example #30
Source File: BackupUtil.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
public static @NonNull String[] generateBackupPassphrase() {
  String[] result = new String[6];
  byte[]   random = new byte[30];

  new SecureRandom().nextBytes(random);

  for (int i=0;i<30;i+=5) {
    result[i/5] = String.format("%05d", ByteUtil.byteArray5ToLong(random, i) % 100000);
  }

  return result;
}