use of im.actor.core.api.ApiEncryptionKey in project actor-platform by actorapp.
the class KeyManagerActor method onMainKeysReady.
private void onMainKeysReady() {
Log.d(TAG, "Main Keys are ready");
//
// Generation required pre keys
//
int missingKeysCount = Math.max(0, Configuration.EPHEMERAL_KEYS_COUNT - ownKeys.getPreKeys().length);
if (missingKeysCount > 0) {
ownKeys = ownKeys.appendPreKeys(ManagedList.of(PrivateKey.GENERATOR, missingKeysCount).toArray(new PrivateKey[0]));
encryptionKeysStorage.addOrUpdateItem(0, ownKeys.toByteArray());
}
//
// Uploading own pre keys
//
final ManagedList<PrivateKey> pendingEphermalKeys = ManagedList.of(ownKeys.getPreKeys()).filter(PrivateKey.NOT_UPLOADED);
if (pendingEphermalKeys.size() > 0) {
ArrayList<ApiEncryptionKey> uploadingKeys = pendingEphermalKeys.map(PrivateKey.TO_API);
ArrayList<ApiEncryptionKeySignature> uploadingSignatures = pendingEphermalKeys.map(PrivateKey.SIGN(ownKeys.getIdentityKey()));
api(new RequestUploadPreKey(ownKeys.getKeyGroupId(), uploadingKeys, uploadingSignatures)).then(new Consumer<ResponseVoid>() {
@Override
public void apply(ResponseVoid responseVoid) {
ownKeys = ownKeys.markAsUploaded(pendingEphermalKeys.toArray(new PrivateKey[pendingEphermalKeys.size()]));
encryptionKeysStorage.addOrUpdateItem(0, ownKeys.toByteArray());
onAllKeysReady();
}
}).failure(new Consumer<Exception>() {
@Override
public void apply(Exception e) {
Log.w(TAG, "Ephemeral keys upload error");
Log.e(TAG, e);
// Ignore. This will freeze all encryption operations.
}
});
} else {
onAllKeysReady();
}
}
use of im.actor.core.api.ApiEncryptionKey in project actor-platform by actorapp.
the class KeyManagerActor method fetchUserPreKey.
/**
* Fetching user's pre key by key id
*
* @param uid User's id
* @param keyGroupId User's key group id
* @param keyId Key id
*/
private Promise<PublicKey> fetchUserPreKey(final int uid, final int keyGroupId, final long keyId) {
User user = users().getValue(uid);
if (user == null) {
throw new RuntimeException("Unable to find user #" + uid);
}
return pickUserGroup(uid, keyGroupId).flatMap(new Function<Tuple2<UserKeysGroup, UserKeys>, Promise<PublicKey>>() {
@Override
public Promise<PublicKey> apply(final Tuple2<UserKeysGroup, UserKeys> keysGroup) {
for (PublicKey p : keysGroup.getT1().getEphemeralKeys()) {
if (p.getKeyId() == keyId) {
return Promise.success(p);
}
}
//
// Downloading pre key
//
ArrayList<Long> ids = new ArrayList<Long>();
ids.add(keyId);
final UserKeysGroup finalKeysGroup = keysGroup.getT1();
return api(new RequestLoadPublicKey(new ApiUserOutPeer(uid, getUser(uid).getAccessHash()), keyGroupId, ids)).map(new Function<ResponsePublicKeys, PublicKey>() {
@Override
public PublicKey apply(ResponsePublicKeys responsePublicKeys) {
if (responsePublicKeys.getPublicKey().size() == 0) {
throw new RuntimeException("Unable to find public key on server");
}
ApiEncryptionKeySignature sig = null;
for (ApiEncryptionKeySignature s : responsePublicKeys.getSignatures()) {
if (s.getKeyId() == keyId && "Ed25519".equals(s.getSignatureAlg())) {
sig = s;
break;
}
}
if (sig == null) {
throw new RuntimeException("Unable to find public key on server");
}
ApiEncryptionKey key = responsePublicKeys.getPublicKey().get(0);
byte[] keyHash = RatchetKeySignature.hashForSignature(key.getKeyId(), key.getKeyAlg(), key.getKeyMaterial());
if (!Curve25519.verifySignature(keysGroup.getT1().getIdentityKey().getPublicKey(), keyHash, sig.getSignature())) {
throw new RuntimeException("Key signature does not isMatch");
}
PublicKey pkey = new PublicKey(keyId, key.getKeyAlg(), key.getKeyMaterial());
UserKeysGroup userKeysGroup = finalKeysGroup.addPublicKey(pkey);
cacheUserKeys(keysGroup.getT2().removeUserKeyGroup(userKeysGroup.getKeyGroupId()).addUserKeyGroup(userKeysGroup));
return pkey;
}
});
}
});
}
use of im.actor.core.api.ApiEncryptionKey in project actor-platform by actorapp.
the class KeyManagerActor method fetchUserPreKey.
/**
* Fetching user's random pre key
*
* @param uid User's id
* @param keyGroupId User's key group id
*/
private Promise<PublicKey> fetchUserPreKey(final int uid, final int keyGroupId) {
return pickUserGroup(uid, keyGroupId).flatMap(new Function<Tuple2<UserKeysGroup, UserKeys>, Promise<PublicKey>>() {
@Override
public Promise<PublicKey> apply(final Tuple2<UserKeysGroup, UserKeys> keyGroups) {
return api(new RequestLoadPrePublicKeys(new ApiUserOutPeer(uid, getUser(uid).getAccessHash()), keyGroupId)).map(new Function<ResponsePublicKeys, PublicKey>() {
@Override
public PublicKey apply(ResponsePublicKeys response) {
if (response.getPublicKey().size() == 0) {
throw new RuntimeException("User doesn't have pre keys");
}
ApiEncryptionKey key = response.getPublicKey().get(0);
ApiEncryptionKeySignature sig = null;
for (ApiEncryptionKeySignature s : response.getSignatures()) {
if (s.getKeyId() == key.getKeyId() && "Ed25519".equals(s.getSignatureAlg())) {
sig = s;
break;
}
}
if (sig == null) {
throw new RuntimeException("Unable to find public key on server");
}
byte[] keyHash = RatchetKeySignature.hashForSignature(key.getKeyId(), key.getKeyAlg(), key.getKeyMaterial());
if (!Curve25519.verifySignature(keyGroups.getT1().getIdentityKey().getPublicKey(), keyHash, sig.getSignature())) {
throw new RuntimeException("Key signature does not isMatch");
}
return new PublicKey(key.getKeyId(), key.getKeyAlg(), key.getKeyMaterial());
}
});
}
});
}
use of im.actor.core.api.ApiEncryptionKey in project actor-platform by actorapp.
the class KeyManagerActor method preStart.
@Override
public void preStart() {
Log.d(TAG, "Starting KeyManager...");
//
// Initialization key storage
//
encryptionKeysStorage = Storage.createKeyValue("encryption_keys");
//
// Initialization own private keys
//
ownKeys = null;
byte[] ownKeysStorage = encryptionKeysStorage.loadItem(0);
if (ownKeysStorage != null) {
try {
ownKeys = new PrivateKeyStorage(ownKeysStorage);
// If we need re-save key storage
if (ownKeys.isWasRegenerated()) {
encryptionKeysStorage.addOrUpdateItem(0, ownKeys.toByteArray());
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (ownKeys == null) {
Curve25519KeyPair identityPrivate = Curve25519.keyGen(Crypto.randomBytes(64));
Curve25519KeyPair key0 = Curve25519.keyGen(Crypto.randomBytes(64));
ownKeys = new PrivateKeyStorage(0, new PrivateKey(RandomUtils.nextRid(), "curve25519", identityPrivate.getPrivateKey(), identityPrivate.getPublicKey()), new PrivateKey[] { new PrivateKey(RandomUtils.nextRid(), "curve25519", key0.getPrivateKey(), key0.getPublicKey()) }, new PrivateKey[0]);
encryptionKeysStorage.addOrUpdateItem(0, ownKeys.toByteArray());
}
if (ownKeys.getKeyGroupId() == 0) {
ApiEncryptionKey identityKey = ownKeys.getIdentityKey().toApiKey();
ArrayList<ApiEncryptionKey> keys = ManagedList.of(ownKeys.getKeys()).map(PrivateKey.TO_API);
ArrayList<ApiEncryptionKeySignature> signatures = ManagedList.of(ownKeys.getKeys()).map(PrivateKey.SIGN(ownKeys.getIdentityKey()));
Log.d(TAG, "Creation of new key group");
api(new RequestCreateNewKeyGroup(identityKey, Configuration.SUPPORTED, keys, signatures)).then(new Consumer<ResponseCreateNewKeyGroup>() {
@Override
public void apply(ResponseCreateNewKeyGroup response) {
ownKeys = ownKeys.setGroupId(response.getKeyGroupId());
encryptionKeysStorage.addOrUpdateItem(0, ownKeys.toByteArray());
onMainKeysReady();
}
}).failure(new Consumer<Exception>() {
@Override
public void apply(Exception e) {
Log.w(TAG, "Keys upload error");
Log.e(TAG, e);
// Just ignore
}
});
} else {
onMainKeysReady();
}
}
use of im.actor.core.api.ApiEncryptionKey in project actor-platform by actorapp.
the class KeyManagerActor method validateUserKeysGroup.
//
// Helper methods
//
private UserKeysGroup validateUserKeysGroup(int uid, ApiEncryptionKeyGroup keyGroup) {
if (!"curve25519".equals(keyGroup.getIdentityKey().getKeyAlg())) {
// Anything other than curve25519 is not supported
Log.w(TAG, "(uid:" + uid + ") Unsupported identity key alg " + keyGroup.getIdentityKey().getKeyAlg());
return null;
}
PublicKey identity = new PublicKey(keyGroup.getIdentityKey().getKeyId(), keyGroup.getIdentityKey().getKeyAlg(), keyGroup.getIdentityKey().getKeyMaterial());
ArrayList<PublicKey> keys = new ArrayList<PublicKey>();
key_loop: for (ApiEncryptionKey key : keyGroup.getKeys()) {
//
for (ApiEncryptionKeySignature sig : keyGroup.getSignatures()) {
if (!sig.getSignatureAlg().equals("Ed25519")) {
// Anything other than Ed25519 is not supported
Log.w(TAG, "(uid:" + uid + ") Unsupported signature algorithm " + sig.getSignatureAlg());
continue;
}
if (sig.getKeyId() != key.getKeyId()) {
continue;
}
byte[] keyForSign = RatchetKeySignature.hashForSignature(key.getKeyId(), key.getKeyAlg(), key.getKeyMaterial());
if (!Curve25519.verifySignature(identity.getPublicKey(), keyForSign, sig.getSignature())) {
Log.w(TAG, "(uid:" + uid + ") Unable to verify signature for " + Crypto.keyHash(key.getKeyMaterial()) + " key");
continue key_loop;
}
}
//
// Adding key to collection
//
keys.add(new PublicKey(key.getKeyId(), key.getKeyAlg(), key.getKeyMaterial()));
}
if (keys.size() == 0) {
Log.w(TAG, "(uid:" + uid + ") No valid keys in key group #" + keyGroup.getKeyGroupId());
}
return new UserKeysGroup(keyGroup.getKeyGroupId(), identity, keys.toArray(new PublicKey[keys.size()]), new PublicKey[0]);
}
Aggregations