コード例 #1
0
  /**
   * Test with random plain text strings and random passwords. UUIDs are used and hence will only
   * cover hex characters (and the separator hyphen).
   *
   * @throws KeyCrypterException
   * @throws UnsupportedEncodingException
   */
  @Test
  public void testKeyCrypterGood2() throws Exception {
    KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);

    System.out.print("EncrypterDecrypterTest: Trying random UUIDs for plainText and passwords :");
    int numberOfTests = 16;
    for (int i = 0; i < numberOfTests; i++) {
      // Create a UUID as the plaintext and use another for the password.
      String plainText = UUID.randomUUID().toString();
      CharSequence password = UUID.randomUUID().toString();

      EncryptedPrivateKey encryptedPrivateKey =
          keyCrypter.encrypt(plainText.getBytes(), keyCrypter.deriveKey(password));

      assertNotNull(encryptedPrivateKey);

      byte[] reconstructedPlainBytes =
          keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(password));
      assertEquals(
          Utils.bytesToHexString(plainText.getBytes()),
          Utils.bytesToHexString(reconstructedPlainBytes));
      System.out.print('.');
    }
    System.out.println(" Done.");
  }
コード例 #2
0
 public static void estimateKeyDerivationTime() {
   // This is run in the background after startup. If we haven't recorded it before, do a key
   // derivation to see
   // how long it takes. This helps us produce better progress feedback, as on Windows we don't
   // currently have a
   // native Scrypt impl and the Java version is ~3 times slower, plus it depends a lot on CPU
   // speed.
   checkGuiThread();
   estimatedKeyDerivationTime = Main.instance.prefs.getExpectedKeyDerivationTime();
   if (estimatedKeyDerivationTime == null) {
     new Thread(
             () -> {
               log.info("Doing background test key derivation");
               KeyCrypterScrypt scrypt = new KeyCrypterScrypt(SCRYPT_PARAMETERS);
               long start = System.currentTimeMillis();
               scrypt.deriveKey("test password");
               long msec = System.currentTimeMillis() - start;
               log.info("Background test key derivation took {}msec", msec);
               Platform.runLater(
                   () -> {
                     estimatedKeyDerivationTime = Duration.ofMillis(msec);
                     Main.instance.prefs.setExpectedKeyDerivationTime(estimatedKeyDerivationTime);
                   });
             })
         .start();
   }
 }
コード例 #3
0
 @Test
 public void deterministicUpgradeEncrypted() throws Exception {
   group = new KeyChainGroup(params);
   final ECKey key = new ECKey();
   group.importKeys(key);
   final KeyCrypterScrypt crypter = new KeyCrypterScrypt();
   final KeyParameter aesKey = crypter.deriveKey("abc");
   assertTrue(group.isDeterministicUpgradeRequired());
   group.encrypt(crypter, aesKey);
   assertTrue(group.isDeterministicUpgradeRequired());
   try {
     group.upgradeToDeterministic(0, null);
     fail();
   } catch (DeterministicUpgradeRequiresPassword e) {
     // Expected.
   }
   group.upgradeToDeterministic(0, aesKey);
   assertFalse(group.isDeterministicUpgradeRequired());
   final DeterministicSeed deterministicSeed = group.getActiveKeyChain().getSeed();
   assertNotNull(deterministicSeed);
   assertTrue(deterministicSeed.isEncrypted());
   byte[] entropy =
       checkNotNull(group.getActiveKeyChain().toDecrypted(aesKey).getSeed()).getEntropyBytes();
   // Check we used the right key: oldest non rotating.
   byte[] truncatedBytes = Arrays.copyOfRange(key.getSecretBytes(), 0, 16);
   assertArrayEquals(entropy, truncatedBytes);
 }
コード例 #4
0
  @Test
  public void testEncryptDecryptBytes2() throws KeyCrypterException {
    KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);

    // Encrypt random bytes of various lengths up to length 50.
    Random random = new Random();

    for (int i = 0; i < 50; i++) {
      byte[] plainBytes = new byte[i];
      random.nextBytes(plainBytes);

      EncryptedPrivateKey encryptedPrivateKey =
          keyCrypter.encrypt(plainBytes, keyCrypter.deriveKey(PASSWORD1));
      assertNotNull(encryptedPrivateKey);
      // log.debug("\nEncrypterDecrypterTest: cipherBytes = \nlength = " + cipherBytes.length +
      // "\n---------------\n" + Utils.bytesToHexString(cipherBytes) + "\n---------------\n");

      byte[] rebornPlainBytes =
          keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(PASSWORD1));

      log.debug("Original: (" + i + ") " + Utils.bytesToHexString(plainBytes));
      log.debug("Reborn1 : (" + i + ") " + Utils.bytesToHexString(rebornPlainBytes));
      assertEquals(Utils.bytesToHexString(plainBytes), Utils.bytesToHexString(rebornPlainBytes));
    }
  }
コード例 #5
0
 @Test
 public void encryptionWhilstEmpty() throws Exception {
   group = new KeyChainGroup(params);
   group.setLookaheadSize(5);
   KeyCrypterScrypt scrypt = new KeyCrypterScrypt(2);
   final KeyParameter aesKey = scrypt.deriveKey("password");
   group.encrypt(scrypt, aesKey);
   assertTrue(group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).isEncrypted());
   final ECKey key = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
   group.decrypt(aesKey);
   assertFalse(checkNotNull(group.findKeyFromPubKey(key.getPubKey())).isEncrypted());
 }
コード例 #6
0
  @Test
  public void testKeyCrypterGood1() throws KeyCrypterException {
    KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);

    // Encrypt.
    EncryptedPrivateKey encryptedPrivateKey =
        keyCrypter.encrypt(TEST_BYTES1, keyCrypter.deriveKey(PASSWORD1));
    assertNotNull(encryptedPrivateKey);

    // Decrypt.
    byte[] reborn = keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(PASSWORD1));
    log.debug("Original: " + Utils.bytesToHexString(TEST_BYTES1));
    log.debug("Reborn  : " + Utils.bytesToHexString(reborn));
    assertEquals(Utils.bytesToHexString(TEST_BYTES1), Utils.bytesToHexString(reborn));
  }
コード例 #7
0
  @Test
  public void serialization() throws Exception {
    assertEquals(INITIAL_KEYS + 1 /* for the seed */, group.serializeToProtobuf().size());
    group = KeyChainGroup.fromProtobufUnencrypted(params, group.serializeToProtobuf());
    group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = group.freshKey(KeyChain.KeyPurpose.CHANGE);
    group.getBloomFilterElementCount();
    List<Protos.Key> protoKeys1 = group.serializeToProtobuf();
    assertEquals(
        INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 1, protoKeys1.size());
    group.importKeys(new ECKey());
    List<Protos.Key> protoKeys2 = group.serializeToProtobuf();
    assertEquals(
        INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 2, protoKeys2.size());

    group = KeyChainGroup.fromProtobufUnencrypted(params, protoKeys1);
    assertEquals(
        INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 1, protoKeys1.size());
    assertTrue(group.hasKey(key1));
    assertTrue(group.hasKey(key2));
    assertEquals(key2, group.currentKey(KeyChain.KeyPurpose.CHANGE));
    assertEquals(key1, group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS));
    group = KeyChainGroup.fromProtobufUnencrypted(params, protoKeys2);
    assertEquals(
        INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 2, protoKeys2.size());
    assertTrue(group.hasKey(key1));
    assertTrue(group.hasKey(key2));

    KeyCrypterScrypt scrypt = new KeyCrypterScrypt(2);
    final KeyParameter aesKey = scrypt.deriveKey("password");
    group.encrypt(scrypt, aesKey);
    List<Protos.Key> protoKeys3 = group.serializeToProtobuf();
    group = KeyChainGroup.fromProtobufEncrypted(params, protoKeys3, scrypt);
    assertTrue(group.isEncrypted());
    assertTrue(group.checkPassword("password"));
    group.decrypt(aesKey);

    // No need for extensive contents testing here, as that's done in the keychain class tests.
  }
コード例 #8
0
  @Test
  public void testEncryptDecryptBytes1() throws KeyCrypterException {
    KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);

    // Encrypt bytes.
    EncryptedPrivateKey encryptedPrivateKey =
        keyCrypter.encrypt(TEST_BYTES1, keyCrypter.deriveKey(PASSWORD1));
    assertNotNull(encryptedPrivateKey);
    log.debug(
        "\nEncrypterDecrypterTest: cipherBytes = \nlength = "
            + encryptedPrivateKey.getEncryptedBytes().length
            + "\n---------------\n"
            + Utils.bytesToHexString(encryptedPrivateKey.getEncryptedBytes())
            + "\n---------------\n");

    byte[] rebornPlainBytes =
        keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(PASSWORD1));

    log.debug("Original: " + Utils.bytesToHexString(TEST_BYTES1));
    log.debug("Reborn1 : " + Utils.bytesToHexString(rebornPlainBytes));
    assertEquals(Utils.bytesToHexString(TEST_BYTES1), Utils.bytesToHexString(rebornPlainBytes));
  }
コード例 #9
0
  @Test
  public void testKeyCrypterWrongPassword() throws KeyCrypterException {
    KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);

    // create a longer encryption string
    StringBuilder stringBuffer = new StringBuilder();
    for (int i = 0; i < 100; i++) {
      stringBuffer.append(i).append(" ").append("The quick brown fox");
    }

    EncryptedPrivateKey encryptedPrivateKey =
        keyCrypter.encrypt(stringBuffer.toString().getBytes(), keyCrypter.deriveKey(PASSWORD2));
    assertNotNull(encryptedPrivateKey);

    try {
      keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(WRONG_PASSWORD));
      // TODO: This test sometimes fails due to relying on padding.
      fail("Decrypt with wrong password did not throw exception");
    } catch (KeyCrypterException ede) {
      assertTrue(ede.getMessage().contains("Could not decrypt"));
    }
  }
コード例 #10
0
public class WalletSetPasswordController {
  private static final Logger log = LoggerFactory.getLogger(WalletSetPasswordController.class);
  public PasswordField pass1, pass2;

  public ProgressIndicator progressMeter;
  public GridPane widgetGrid;
  public HBox buttonHBox;
  public Label explanationLabel;

  public Main.OverlayUI overlayUI;
  // These params were determined empirically on a top-range (as of 2014) MacBook Pro with native
  // scrypt support,
  // using the scryptenc command line tool from the original scrypt distribution, given a memory
  // limit of 40mb.
  public static final Protos.ScryptParameters SCRYPT_PARAMETERS =
      Protos.ScryptParameters.newBuilder()
          .setP(6)
          .setR(8)
          .setN(32768)
          .setSalt(ByteString.copyFrom(KeyCrypterScrypt.randomSalt()))
          .build();

  public void initialize() {
    progressMeter.setOpacity(0);
  }

  public static Duration estimatedKeyDerivationTime = null;

  public static void estimateKeyDerivationTime() {
    // This is run in the background after startup. If we haven't recorded it before, do a key
    // derivation to see
    // how long it takes. This helps us produce better progress feedback, as on Windows we don't
    // currently have a
    // native Scrypt impl and the Java version is ~3 times slower, plus it depends a lot on CPU
    // speed.
    checkGuiThread();
    estimatedKeyDerivationTime = Main.instance.prefs.getExpectedKeyDerivationTime();
    if (estimatedKeyDerivationTime == null) {
      new Thread(
              () -> {
                log.info("Doing background test key derivation");
                KeyCrypterScrypt scrypt = new KeyCrypterScrypt(SCRYPT_PARAMETERS);
                long start = System.currentTimeMillis();
                scrypt.deriveKey("test password");
                long msec = System.currentTimeMillis() - start;
                log.info("Background test key derivation took {}msec", msec);
                Platform.runLater(
                    () -> {
                      estimatedKeyDerivationTime = Duration.ofMillis(msec);
                      Main.instance.prefs.setExpectedKeyDerivationTime(estimatedKeyDerivationTime);
                    });
              })
          .start();
    }
  }

  @FXML
  public void setPasswordClicked(ActionEvent event) {
    if (!pass1.getText().equals(pass2.getText())) {
      informationalAlert(tr("Passwords do not match"), tr("Try re-typing your chosen passwords."));
      return;
    }
    String password = pass1.getText();
    // This is kind of arbitrary and we could do much more to help people pick strong passwords.
    if (password.length() < 4) {
      informationalAlert(
          tr("Password too short"),
          tr("You need to pick a password at least five characters or longer."));
      return;
    }

    fadeIn(progressMeter);
    fadeOut(widgetGrid);
    fadeOut(explanationLabel);
    fadeOut(buttonHBox);

    KeyCrypterScrypt scrypt = new KeyCrypterScrypt(SCRYPT_PARAMETERS);

    // Deriving the actual key runs on a background thread. 500msec is empirical on my laptop
    // (actual val is more like 333 but we give padding time).
    KeyDerivationTasks tasks =
        new KeyDerivationTasks(scrypt, password, estimatedKeyDerivationTime) {
          @Override
          protected void onFinish(KeyParameter aesKey, int timeTakenMsec) {
            // Write the target time to the wallet so we can make the progress bar work when
            // entering the password.
            WalletPasswordController.setTargetTime(Duration.ofMillis(timeTakenMsec));
            // The actual encryption part doesn't take very long as most private keys are derived on
            // demand.
            log.info("Key derived, now encrypting");
            Main.bitcoin.wallet().encrypt(scrypt, aesKey);
            log.info("Encryption done");
            informationalAlert(
                tr("Wallet encrypted"),
                tr("You can remove the password at any time from the settings screen."));
            overlayUI.done();
          }
        };
    progressMeter.progressProperty().bind(tasks.progress);
    tasks.start();
  }

  @FXML
  public void closeClicked(ActionEvent event) {
    overlayUI.done();
  }
}
コード例 #11
0
  public void encryption(boolean withImported) throws Exception {
    Utils.rollMockClock(0);
    long now = Utils.currentTimeSeconds();
    ECKey a = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    assertEquals(now, group.getEarliestKeyCreationTime());
    Utils.rollMockClock(-86400);
    long yesterday = Utils.currentTimeSeconds();
    ECKey b = new ECKey();

    assertFalse(group.isEncrypted());
    try {
      group.checkPassword("foo"); // Cannot check password of an unencrypted group.
      fail();
    } catch (IllegalStateException e) {
    }
    if (withImported) {
      assertEquals(now, group.getEarliestKeyCreationTime());
      group.importKeys(b);
      assertEquals(yesterday, group.getEarliestKeyCreationTime());
    }
    KeyCrypterScrypt scrypt = new KeyCrypterScrypt(2);
    final KeyParameter aesKey = scrypt.deriveKey("password");
    group.encrypt(scrypt, aesKey);
    assertTrue(group.isEncrypted());
    assertTrue(group.checkPassword("password"));
    assertFalse(group.checkPassword("wrong password"));
    final ECKey ea = group.findKeyFromPubKey(a.getPubKey());
    assertTrue(checkNotNull(ea).isEncrypted());
    if (withImported) {
      assertTrue(checkNotNull(group.findKeyFromPubKey(b.getPubKey())).isEncrypted());
      assertEquals(yesterday, group.getEarliestKeyCreationTime());
    } else {
      assertEquals(now, group.getEarliestKeyCreationTime());
    }
    try {
      ea.sign(Sha256Hash.ZERO_HASH);
      fail();
    } catch (ECKey.KeyIsEncryptedException e) {
      // Ignored.
    }
    if (withImported) {
      ECKey c = new ECKey();
      try {
        group.importKeys(c);
        fail();
      } catch (KeyCrypterException e) {
      }
      group.importKeysAndEncrypt(ImmutableList.of(c), aesKey);
      ECKey ec = group.findKeyFromPubKey(c.getPubKey());
      try {
        group.importKeysAndEncrypt(ImmutableList.of(ec), aesKey);
        fail();
      } catch (IllegalArgumentException e) {
      }
    }

    try {
      group.decrypt(scrypt.deriveKey("WRONG PASSWORD"));
      fail();
    } catch (KeyCrypterException e) {
    }

    group.decrypt(aesKey);
    assertFalse(group.isEncrypted());
    assertFalse(checkNotNull(group.findKeyFromPubKey(a.getPubKey())).isEncrypted());
    if (withImported) {
      assertFalse(checkNotNull(group.findKeyFromPubKey(b.getPubKey())).isEncrypted());
      assertEquals(yesterday, group.getEarliestKeyCreationTime());
    } else {
      assertEquals(now, group.getEarliestKeyCreationTime());
    }
  }