InMemoryKeyStore.java

  1. /*
  2.  * @copyright defined in LICENSE.txt
  3.  */

  4. package hera.keystore;

  5. import static org.slf4j.LoggerFactory.getLogger;

  6. import hera.annotation.ApiAudience;
  7. import hera.annotation.ApiStability;
  8. import hera.api.model.Authentication;
  9. import hera.api.model.EncryptedPrivateKey;
  10. import hera.api.model.Identity;
  11. import hera.exception.InvalidAuthenticationException;
  12. import hera.exception.KeyStoreException;
  13. import hera.key.AergoKey;
  14. import hera.key.Signer;
  15. import hera.util.Sha256Utils;
  16. import java.util.ArrayList;
  17. import java.util.HashMap;
  18. import java.util.HashSet;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import org.slf4j.Logger;

  23. @ApiAudience.Public
  24. @ApiStability.Unstable
  25. public class InMemoryKeyStore implements KeyStore {

  26.   protected final transient Logger logger = getLogger(getClass());

  27.   protected final Set<Identity> storedIdentities = new HashSet<>();
  28.   protected final Map<String, EncryptedPrivateKey> hashedAuth2Encrypted = new HashMap<>();

  29.   @Override
  30.   public void save(final Authentication authentication, final AergoKey key) {
  31.     try {
  32.       logger.debug("Save with authentication: {}, key: {}", authentication, key);
  33.       final String digested = digest(authentication);

  34.       synchronized (this) {
  35.         if (this.storedIdentities.contains(authentication.getIdentity())) {
  36.           throw new InvalidAuthenticationException("Identity already exists");
  37.         }
  38.         if (this.hashedAuth2Encrypted.containsKey(digested)) {
  39.           throw new InvalidAuthenticationException("Invalid authentication");
  40.         }

  41.         final EncryptedPrivateKey encryptedKey = key.export(authentication.getPassword());
  42.         this.storedIdentities.add(authentication.getIdentity());
  43.         this.hashedAuth2Encrypted.put(digested, encryptedKey);
  44.       }
  45.     } catch (InvalidAuthenticationException e) {
  46.       throw e;
  47.     } catch (final Exception e) {
  48.       throw new KeyStoreException(e);
  49.     }
  50.   }

  51.   @Override
  52.   public Signer load(final Authentication authentication) {
  53.     try {
  54.       logger.debug("Unlock with authentication: {}", authentication);
  55.       final String digested = digest(authentication);

  56.       synchronized (this) {
  57.         if (false == this.hashedAuth2Encrypted.containsKey(digested)) {
  58.           throw new InvalidAuthenticationException("Invalid authentication");
  59.         }

  60.         final EncryptedPrivateKey encrypted = hashedAuth2Encrypted.get(digested);
  61.         final AergoKey decrypted = AergoKey.of(encrypted, authentication.getPassword());
  62.         return decrypted;
  63.       }
  64.     } catch (InvalidAuthenticationException e) {
  65.       throw e;
  66.     } catch (Exception e) {
  67.       throw new KeyStoreException(e);
  68.     }
  69.   }

  70.   @Override
  71.   public void remove(final Authentication authentication) {
  72.     try {
  73.       logger.debug("Remove aergo key with authentication: {}", authentication);
  74.       final String digested = digest(authentication);

  75.       synchronized (this) {
  76.         if (false == this.hashedAuth2Encrypted.containsKey(digested)) {
  77.           throw new InvalidAuthenticationException("Invalid authentication");
  78.         }

  79.         this.storedIdentities.remove(authentication.getIdentity());
  80.         this.hashedAuth2Encrypted.remove(digested);
  81.       }
  82.     } catch (InvalidAuthenticationException e) {
  83.       throw e;
  84.     } catch (final Exception e) {
  85.       throw new KeyStoreException(e);
  86.     }
  87.   }

  88.   @Override
  89.   public EncryptedPrivateKey export(final Authentication authentication, final String password) {
  90.     try {
  91.       logger.debug("Export key with authentication: {}", authentication);
  92.       final String digested = digest(authentication);

  93.       synchronized (this) {
  94.         if (false == hashedAuth2Encrypted.containsKey(digested)) {
  95.           throw new InvalidAuthenticationException("Invalid authentication");
  96.         }

  97.         final EncryptedPrivateKey encrypted = hashedAuth2Encrypted.get(digested);
  98.         final AergoKey decrypted = AergoKey.of(encrypted, authentication.getPassword());
  99.         return decrypted.export(password);
  100.       }
  101.     } catch (InvalidAuthenticationException e) {
  102.       throw e;
  103.     } catch (final Exception e) {
  104.       throw new KeyStoreException(e);
  105.     }
  106.   }

  107.   @Override
  108.   public List<Identity> listIdentities() {
  109.     try {
  110.       return new ArrayList<>(this.storedIdentities);
  111.     } catch (final Exception e) {
  112.       throw new KeyStoreException(e);
  113.     }
  114.   }

  115.   @Override
  116.   public void store(final String path, final char[] password) {
  117.     // do nothing
  118.   }

  119.   protected String digest(final Authentication authentication) {
  120.     final byte[] rawIdentity = authentication.getIdentity().getValue().getBytes();
  121.     final byte[] rawPassword = authentication.getPassword().getBytes();
  122.     final byte[] plaintext = new byte[rawIdentity.length + rawPassword.length];
  123.     System.arraycopy(rawIdentity, 0, plaintext, 0, rawIdentity.length);
  124.     System.arraycopy(rawPassword, 0, plaintext, rawIdentity.length, rawPassword.length);
  125.     return new String(Sha256Utils.digest(plaintext));
  126.   }

  127. }