1 package org
.asamk
.signal
.storage
.protocol
;
3 import com
.fasterxml
.jackson
.core
.JsonGenerator
;
4 import com
.fasterxml
.jackson
.core
.JsonParser
;
5 import com
.fasterxml
.jackson
.databind
.DeserializationContext
;
6 import com
.fasterxml
.jackson
.databind
.JsonDeserializer
;
7 import com
.fasterxml
.jackson
.databind
.JsonNode
;
8 import com
.fasterxml
.jackson
.databind
.JsonSerializer
;
9 import com
.fasterxml
.jackson
.databind
.SerializerProvider
;
11 import org
.asamk
.signal
.TrustLevel
;
12 import org
.whispersystems
.libsignal
.IdentityKey
;
13 import org
.whispersystems
.libsignal
.IdentityKeyPair
;
14 import org
.whispersystems
.libsignal
.InvalidKeyException
;
15 import org
.whispersystems
.libsignal
.SignalProtocolAddress
;
16 import org
.whispersystems
.libsignal
.state
.IdentityKeyStore
;
17 import org
.whispersystems
.signalservice
.internal
.util
.Base64
;
19 import java
.io
.IOException
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Date
;
22 import java
.util
.HashMap
;
23 import java
.util
.List
;
26 public class JsonIdentityKeyStore
implements IdentityKeyStore
{
28 private final Map
<String
, List
<Identity
>> trustedKeys
= new HashMap
<>();
30 private final IdentityKeyPair identityKeyPair
;
31 private final int localRegistrationId
;
33 public JsonIdentityKeyStore(IdentityKeyPair identityKeyPair
, int localRegistrationId
) {
34 this.identityKeyPair
= identityKeyPair
;
35 this.localRegistrationId
= localRegistrationId
;
39 public IdentityKeyPair
getIdentityKeyPair() {
40 return identityKeyPair
;
44 public int getLocalRegistrationId() {
45 return localRegistrationId
;
49 public boolean saveIdentity(SignalProtocolAddress address
, IdentityKey identityKey
) {
50 return saveIdentity(address
.getName(), identityKey
, TrustLevel
.TRUSTED_UNVERIFIED
, null);
54 * Adds or updates the given identityKey for the user name and sets the trustLevel and added timestamp.
56 * @param name User name, i.e. phone number
57 * @param identityKey The user's public key
59 * @param added Added timestamp, if null and the key is newly added, the current time is used.
61 public boolean saveIdentity(String name
, IdentityKey identityKey
, TrustLevel trustLevel
, Date added
) {
62 List
<Identity
> identities
= trustedKeys
.get(name
);
63 if (identities
== null) {
64 identities
= new ArrayList
<>();
65 trustedKeys
.put(name
, identities
);
67 for (Identity id
: identities
) {
68 if (!id
.identityKey
.equals(identityKey
))
71 if (id
.trustLevel
.compareTo(trustLevel
) < 0) {
72 id
.trustLevel
= trustLevel
;
80 identities
.add(new Identity(identityKey
, trustLevel
, added
!= null ? added
: new Date()));
85 public boolean isTrustedIdentity(SignalProtocolAddress address
, IdentityKey identityKey
, Direction direction
) {
86 // TODO implement possibility for different handling of incoming/outgoing trust decisions
87 List
<Identity
> identities
= trustedKeys
.get(address
.getName());
88 if (identities
== null) {
93 for (Identity id
: identities
) {
94 if (id
.identityKey
.equals(identityKey
)) {
95 return id
.isTrusted();
103 public IdentityKey
getIdentity(SignalProtocolAddress address
) {
104 List
<Identity
> identities
= trustedKeys
.get(address
.getName());
105 if (identities
== null || identities
.size() == 0) {
110 Identity maxIdentity
= null;
111 for (Identity id
: identities
) {
112 final long time
= id
.getDateAdded().getTime();
113 if (maxIdentity
== null || maxDate
<= time
) {
118 return maxIdentity
.getIdentityKey();
121 public Map
<String
, List
<Identity
>> getIdentities() {
126 public List
<Identity
> getIdentities(String name
) {
128 return trustedKeys
.get(name
);
131 public static class JsonIdentityKeyStoreDeserializer
extends JsonDeserializer
<JsonIdentityKeyStore
> {
134 public JsonIdentityKeyStore
deserialize(JsonParser jsonParser
, DeserializationContext deserializationContext
) throws IOException
{
135 JsonNode node
= jsonParser
.getCodec().readTree(jsonParser
);
138 int localRegistrationId
= node
.get("registrationId").asInt();
139 IdentityKeyPair identityKeyPair
= new IdentityKeyPair(Base64
.decode(node
.get("identityKey").asText()));
141 JsonIdentityKeyStore keyStore
= new JsonIdentityKeyStore(identityKeyPair
, localRegistrationId
);
143 JsonNode trustedKeysNode
= node
.get("trustedKeys");
144 if (trustedKeysNode
.isArray()) {
145 for (JsonNode trustedKey
: trustedKeysNode
) {
146 String trustedKeyName
= trustedKey
.get("name").asText();
148 IdentityKey id
= new IdentityKey(Base64
.decode(trustedKey
.get("identityKey").asText()), 0);
149 TrustLevel trustLevel
= trustedKey
.has("trustLevel") ? TrustLevel
.fromInt(trustedKey
.get("trustLevel").asInt()) : TrustLevel
.TRUSTED_UNVERIFIED
;
150 Date added
= trustedKey
.has("addedTimestamp") ?
new Date(trustedKey
.get("addedTimestamp").asLong()) : new Date();
151 keyStore
.saveIdentity(trustedKeyName
, id
, trustLevel
, added
);
152 } catch (InvalidKeyException
| IOException e
) {
153 System
.out
.println(String
.format("Error while decoding key for: %s", trustedKeyName
));
159 } catch (InvalidKeyException e
) {
160 throw new IOException(e
);
165 public static class JsonIdentityKeyStoreSerializer
extends JsonSerializer
<JsonIdentityKeyStore
> {
168 public void serialize(JsonIdentityKeyStore jsonIdentityKeyStore
, JsonGenerator json
, SerializerProvider serializerProvider
) throws IOException
{
169 json
.writeStartObject();
170 json
.writeNumberField("registrationId", jsonIdentityKeyStore
.getLocalRegistrationId());
171 json
.writeStringField("identityKey", Base64
.encodeBytes(jsonIdentityKeyStore
.getIdentityKeyPair().serialize()));
172 json
.writeArrayFieldStart("trustedKeys");
173 for (Map
.Entry
<String
, List
<Identity
>> trustedKey
: jsonIdentityKeyStore
.trustedKeys
.entrySet()) {
174 for (Identity id
: trustedKey
.getValue()) {
175 json
.writeStartObject();
176 json
.writeStringField("name", trustedKey
.getKey());
177 json
.writeStringField("identityKey", Base64
.encodeBytes(id
.identityKey
.serialize()));
178 json
.writeNumberField("trustLevel", id
.trustLevel
.ordinal());
179 json
.writeNumberField("addedTimestamp", id
.added
.getTime());
180 json
.writeEndObject();
183 json
.writeEndArray();
184 json
.writeEndObject();
188 public class Identity
{
190 IdentityKey identityKey
;
191 TrustLevel trustLevel
;
194 public Identity(IdentityKey identityKey
, TrustLevel trustLevel
) {
195 this.identityKey
= identityKey
;
196 this.trustLevel
= trustLevel
;
197 this.added
= new Date();
200 Identity(IdentityKey identityKey
, TrustLevel trustLevel
, Date added
) {
201 this.identityKey
= identityKey
;
202 this.trustLevel
= trustLevel
;
206 boolean isTrusted() {
207 return trustLevel
== TrustLevel
.TRUSTED_UNVERIFIED
||
208 trustLevel
== TrustLevel
.TRUSTED_VERIFIED
;
211 public IdentityKey
getIdentityKey() {
212 return this.identityKey
;
215 public TrustLevel
getTrustLevel() {
216 return this.trustLevel
;
219 public Date
getDateAdded() {
223 public byte[] getFingerprint() {
224 return identityKey
.getPublicKey().serialize();