mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
clean fingerprint
This commit is contained in:
parent
a11173676f
commit
c07056f385
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.util.ByteUtil;
|
|
||||||
|
|
||||||
public class DisplayableFingerprint {
|
|
||||||
|
|
||||||
private final String localFingerprintNumbers;
|
|
||||||
private final String remoteFingerprintNumbers;
|
|
||||||
|
|
||||||
DisplayableFingerprint(byte[] localFingerprint, byte[] remoteFingerprint)
|
|
||||||
{
|
|
||||||
this.localFingerprintNumbers = getDisplayStringFor(localFingerprint);
|
|
||||||
this.remoteFingerprintNumbers = getDisplayStringFor(remoteFingerprint);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayText() {
|
|
||||||
if (localFingerprintNumbers.compareTo(remoteFingerprintNumbers) <= 0) {
|
|
||||||
return localFingerprintNumbers + remoteFingerprintNumbers;
|
|
||||||
} else {
|
|
||||||
return remoteFingerprintNumbers + localFingerprintNumbers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDisplayStringFor(byte[] fingerprint) {
|
|
||||||
return getEncodedChunk(fingerprint, 0) +
|
|
||||||
getEncodedChunk(fingerprint, 5) +
|
|
||||||
getEncodedChunk(fingerprint, 10) +
|
|
||||||
getEncodedChunk(fingerprint, 15) +
|
|
||||||
getEncodedChunk(fingerprint, 20) +
|
|
||||||
getEncodedChunk(fingerprint, 25);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getEncodedChunk(byte[] hash, int offset) {
|
|
||||||
long chunk = ByteUtil.byteArray5ToLong(hash, offset) % 100000;
|
|
||||||
return String.format("%05d", chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.fingerprint.DisplayableFingerprint;
|
|
||||||
import org.session.libsignal.libsignal.fingerprint.ScannableFingerprint;
|
|
||||||
|
|
||||||
public class Fingerprint {
|
|
||||||
|
|
||||||
private final DisplayableFingerprint displayableFingerprint;
|
|
||||||
private final ScannableFingerprint scannableFingerprint;
|
|
||||||
|
|
||||||
public Fingerprint(DisplayableFingerprint displayableFingerprint,
|
|
||||||
ScannableFingerprint scannableFingerprint)
|
|
||||||
{
|
|
||||||
this.displayableFingerprint = displayableFingerprint;
|
|
||||||
this.scannableFingerprint = scannableFingerprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A text fingerprint that can be displayed and compared remotely.
|
|
||||||
*/
|
|
||||||
public DisplayableFingerprint getDisplayableFingerprint() {
|
|
||||||
return displayableFingerprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A scannable fingerprint that can be scanned anc compared locally.
|
|
||||||
*/
|
|
||||||
public ScannableFingerprint getScannableFingerprint() {
|
|
||||||
return scannableFingerprint;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.IdentityKey;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface FingerprintGenerator {
|
|
||||||
public Fingerprint createFor(String localStableIdentifier, IdentityKey localIdentityKey,
|
|
||||||
String remoteStableIdentifier, IdentityKey remoteIdentityKey);
|
|
||||||
|
|
||||||
public Fingerprint createFor(String localStableIdentifier, List<IdentityKey> localIdentityKey,
|
|
||||||
String remoteStableIdentifier, List<IdentityKey> remoteIdentityKey);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
public class FingerprintIdentifierMismatchException extends Exception {
|
|
||||||
|
|
||||||
private final String localIdentifier;
|
|
||||||
private final String remoteIdentifier;
|
|
||||||
private final String scannedLocalIdentifier;
|
|
||||||
private final String scannedRemoteIdentifier;
|
|
||||||
|
|
||||||
public FingerprintIdentifierMismatchException(String localIdentifier, String remoteIdentifier,
|
|
||||||
String scannedLocalIdentifier, String scannedRemoteIdentifier)
|
|
||||||
{
|
|
||||||
this.localIdentifier = localIdentifier;
|
|
||||||
this.remoteIdentifier = remoteIdentifier;
|
|
||||||
this.scannedLocalIdentifier = scannedLocalIdentifier;
|
|
||||||
this.scannedRemoteIdentifier = scannedRemoteIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getScannedRemoteIdentifier() {
|
|
||||||
return scannedRemoteIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getScannedLocalIdentifier() {
|
|
||||||
return scannedLocalIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRemoteIdentifier() {
|
|
||||||
return remoteIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLocalIdentifier() {
|
|
||||||
return localIdentifier;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
public class FingerprintParsingException extends Exception {
|
|
||||||
|
|
||||||
public FingerprintParsingException(Exception nested) {
|
|
||||||
super(nested);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
public class FingerprintVersionMismatchException extends Exception {
|
|
||||||
|
|
||||||
private final int theirVersion;
|
|
||||||
private final int ourVersion;
|
|
||||||
|
|
||||||
public FingerprintVersionMismatchException(int theirVersion, int ourVersion) {
|
|
||||||
super();
|
|
||||||
this.theirVersion = theirVersion;
|
|
||||||
this.ourVersion = ourVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTheirVersion() {
|
|
||||||
return theirVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOurVersion() {
|
|
||||||
return ourVersion;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.IdentityKey;
|
|
||||||
import org.session.libsignal.libsignal.util.ByteUtil;
|
|
||||||
import org.session.libsignal.libsignal.util.IdentityKeyComparator;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NumericFingerprintGenerator implements FingerprintGenerator {
|
|
||||||
|
|
||||||
private static final int FINGERPRINT_VERSION = 0;
|
|
||||||
|
|
||||||
private final int iterations;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a fingerprint generator for 60 digit numerics.
|
|
||||||
*
|
|
||||||
* @param iterations The number of internal iterations to perform in the process of
|
|
||||||
* generating a fingerprint. This needs to be constant, and synchronized
|
|
||||||
* across all clients.
|
|
||||||
*
|
|
||||||
* The higher the iteration count, the higher the security level:
|
|
||||||
*
|
|
||||||
* - 1024 ~ 109.7 bits
|
|
||||||
* - 1400 > 110 bits
|
|
||||||
* - 5200 > 112 bits
|
|
||||||
*/
|
|
||||||
public NumericFingerprintGenerator(int iterations) {
|
|
||||||
this.iterations = iterations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a scannable and displayble fingerprint.
|
|
||||||
*
|
|
||||||
* @param localStableIdentifier The client's "stable" identifier.
|
|
||||||
* @param localIdentityKey The client's identity key.
|
|
||||||
* @param remoteStableIdentifier The remote party's "stable" identifier.
|
|
||||||
* @param remoteIdentityKey The remote party's identity key.
|
|
||||||
* @return A unique fingerprint for this conversation.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Fingerprint createFor(String localStableIdentifier, final IdentityKey localIdentityKey,
|
|
||||||
String remoteStableIdentifier, final IdentityKey remoteIdentityKey)
|
|
||||||
{
|
|
||||||
return createFor(localStableIdentifier,
|
|
||||||
new LinkedList<IdentityKey>() {{
|
|
||||||
add(localIdentityKey);
|
|
||||||
}},
|
|
||||||
remoteStableIdentifier,
|
|
||||||
new LinkedList<IdentityKey>() {{
|
|
||||||
add(remoteIdentityKey);
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a scannable and displayble fingerprint for logical identities that have multiple
|
|
||||||
* physical keys.
|
|
||||||
*
|
|
||||||
* Do not trust the output of this unless you've been through the device consistency process
|
|
||||||
* for the provided localIdentityKeys.
|
|
||||||
*
|
|
||||||
* @param localStableIdentifier The client's "stable" identifier.
|
|
||||||
* @param localIdentityKeys The client's collection of physical identity keys.
|
|
||||||
* @param remoteStableIdentifier The remote party's "stable" identifier.
|
|
||||||
* @param remoteIdentityKeys The remote party's collection of physical identity key.
|
|
||||||
* @return A unique fingerprint for this conversation.
|
|
||||||
*/
|
|
||||||
public Fingerprint createFor(String localStableIdentifier, List<IdentityKey> localIdentityKeys,
|
|
||||||
String remoteStableIdentifier, List<IdentityKey> remoteIdentityKeys)
|
|
||||||
{
|
|
||||||
byte[] localFingerprint = getFingerprint(iterations, localStableIdentifier, localIdentityKeys);
|
|
||||||
byte[] remoteFingerprint = getFingerprint(iterations, remoteStableIdentifier, remoteIdentityKeys);
|
|
||||||
|
|
||||||
DisplayableFingerprint displayableFingerprint = new DisplayableFingerprint(localFingerprint,
|
|
||||||
remoteFingerprint);
|
|
||||||
|
|
||||||
ScannableFingerprint scannableFingerprint = new ScannableFingerprint(localFingerprint,
|
|
||||||
remoteFingerprint);
|
|
||||||
|
|
||||||
return new Fingerprint(displayableFingerprint, scannableFingerprint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getFingerprint(int iterations, String 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.getBytes());
|
|
||||||
|
|
||||||
for (int i=0;i<iterations;i++) {
|
|
||||||
digest.update(hash);
|
|
||||||
hash = digest.digest(publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getLogicalKeyBytes(List<IdentityKey> identityKeys) {
|
|
||||||
ArrayList<IdentityKey> sortedIdentityKeys = new ArrayList<IdentityKey>(identityKeys);
|
|
||||||
Collections.sort(sortedIdentityKeys, new IdentityKeyComparator());
|
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
for (IdentityKey identityKey : sortedIdentityKeys) {
|
|
||||||
byte[] publicKeyBytes = identityKey.getPublicKey().serialize();
|
|
||||||
baos.write(publicKeyBytes, 0, publicKeyBytes.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.libsignal.fingerprint;
|
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.fingerprint.FingerprintParsingException;
|
|
||||||
import org.session.libsignal.libsignal.fingerprint.FingerprintProtos.CombinedFingerprints;
|
|
||||||
import org.session.libsignal.libsignal.fingerprint.FingerprintProtos.LogicalFingerprint;
|
|
||||||
import org.session.libsignal.libsignal.fingerprint.FingerprintVersionMismatchException;
|
|
||||||
import org.session.libsignal.libsignal.util.ByteUtil;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
|
|
||||||
public class ScannableFingerprint {
|
|
||||||
|
|
||||||
private static final int VERSION = 1;
|
|
||||||
|
|
||||||
private final CombinedFingerprints fingerprints;
|
|
||||||
|
|
||||||
ScannableFingerprint(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.fingerprints = CombinedFingerprints.newBuilder()
|
|
||||||
.setVersion(VERSION)
|
|
||||||
.setLocalFingerprint(localFingerprint)
|
|
||||||
.setRemoteFingerprint(remoteFingerprint)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A byte string to be displayed in a QR code.
|
|
||||||
*/
|
|
||||||
public byte[] getSerialized() {
|
|
||||||
return fingerprints.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare a scanned QR code with what we expect.
|
|
||||||
*
|
|
||||||
* @param scannedFingerprintData The scanned data
|
|
||||||
* @return True if matching, otehrwise false.
|
|
||||||
* @throws FingerprintVersionMismatchException if the scanned fingerprint is the wrong version.
|
|
||||||
*/
|
|
||||||
public boolean compareTo(byte[] scannedFingerprintData)
|
|
||||||
throws FingerprintVersionMismatchException,
|
|
||||||
FingerprintParsingException
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
CombinedFingerprints scanned = CombinedFingerprints.parseFrom(scannedFingerprintData);
|
|
||||||
|
|
||||||
if (!scanned.hasRemoteFingerprint() || !scanned.hasLocalFingerprint() ||
|
|
||||||
!scanned.hasVersion() || scanned.getVersion() != VERSION)
|
|
||||||
{
|
|
||||||
throw new FingerprintVersionMismatchException(scanned.getVersion(), VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
return MessageDigest.isEqual(fingerprints.getLocalFingerprint().getContent().toByteArray(), scanned.getRemoteFingerprint().getContent().toByteArray()) &&
|
|
||||||
MessageDigest.isEqual(fingerprints.getRemoteFingerprint().getContent().toByteArray(), scanned.getLocalFingerprint().getContent().toByteArray());
|
|
||||||
} catch (InvalidProtocolBufferException e) {
|
|
||||||
throw new FingerprintParsingException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user