0

皆様からのコメントありがとうございます。

しかし、私はこの問題を説明しなければなりません。

安全性が低下する可能性があるため、修正ランダムジェネレーターを使用して暗号化の結果を比較すべきではないことはわかっています。ただ、あくまでテストでやりたいだけで、実走ではランダムという独自の仕組みを使っています。

場合は、次の手順でアカウント/パスワードを使用してサーバーにログインする必要がある場合です。

  1. サーバーから情報を取得します: abcom/get_cipher.cgi。
  2. 応答を受け取り、それを解析し、情報を取得して暗号を作成します。
  3. 暗号を使用してアカウント/パスワードを暗号化し、次の URL abcom/login.cgi?encrypted={encrypted_account_password} を構成します。

これは複雑なプロセスであり、サーバーにプロトコルの変更を要求することはできません。ログインプロセス全体をテストしたい。したがって、偽のアカウント/パスワードを提供し、結果を解読せずに生成された URL が正しいかどうかを確認しようとしました (結果を解読する場合、このテスト ケースでは、暗号化された結果を解読し、URL を解析する必要があることを意味します)。関連情報を抽出すると、テストに関係のない情報が多すぎます. さらに、ログイン プロセスに何らかの変更を加えると、テスト ケースの解読および解析プロセスを変更する必要がある場合があります.)

つまり、ハッシュ関数は私には適していません。(元のログイン プロセスはハッシュを使用しないため、テスト ケースでテストしたくありません。さらに、ハッシュの結果が正しいことを確認したとしても、ログイン プロセスが正しいことを証明するものではありません。)

===元の質問は次のとおりです===

ログインが必要なプログラムがあります。ネットワーク上でパスワードを平文で転送しないようにするには、パスワードを暗号化する必要があります。つまり、ログイン プロセスには暗号化フェーズが含まれます。

次に、ログイン プロセス全体のテスト ケースを作成します。同じアカウントとパスワードを使えば暗号化結果は同じだと思います。

暗号化プロセスで SecureRandom を使用する可能性があるため、次のコードのように Mockito による偽の SecureRandom を記述します。

private static final long RANDOM_SEED = 3670875202692512518L;
private Random generateRandomWithFixSeed() {
    Random random = new Random(RANDOM_SEED);
    return random;
}

private SecureRandom generateSecureRandomWithFixSeed() {
    final Random random = generateRandomWithFixSeed();
    final SecureRandom secureRandom = new SecureRandom();
    final SecureRandom spySecureRandom = Mockito.spy(secureRandom);

    Mockito.doAnswer(new Answer<Object>() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            Object[] args = invocation.getArguments();
            byte[] bytes = (byte[]) args[0];
            random.nextBytes(bytes);
            return bytes;
        }
    })
            .when(spySecureRandom)
            .nextBytes(Matchers.<byte[]>anyObject());

    return spySecureRandom;
}

@Test
public void test_SecureRandom_WithFixSeed() {
    final SecureRandom secureRandom1 = generateSecureRandomWithFixSeed();
    final SecureRandom secureRandom2 = generateSecureRandomWithFixSeed();

    final byte[] bytes1 = new byte[20];
    final byte[] bytes2 = new byte[20];

    secureRandom1.nextBytes(bytes1);
    secureRandom2.nextBytes(bytes2);

    boolean isTheSameSeries = true;
    for(int i = 0; i < 20; i++) {
        isTheSameSeries &= (bytes1[i]==bytes2[i]);
    }

    assertThat(isTheSameSeries, is(true));
}

generateRandomWithFixSeed()は、同じキーを持つ Random を新しく作成するため、同じ結果が生成されます。generateSecureRandomWithFixSeed()は、Makito を使用して関数呼び出し nextBytes() を検出し、常に乱数の結果を返します。テストtest_SecureRandom_WithFixSeed()も、2 つの異なる SecureRandom インスタンスが同じ結果を生成することを示しています。

ただし、次のように暗号で generateSecureRandomWithFixSeed() を使用すると、常に同じ結果が返されるとは限りません。

    @Test
public void test_cipher() {
    final SecureRandom secureRandomWithFixSeed = generateSecureRandomWithFixSeed();

    final String pkcs = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv7n+/uWHHVC7229QLEObeH0vUcOagavDukf/gkveqgZsszzGkZQaXfsrjdPiCnvjozCy1tbnLu5EInDy4w8B+a9gtK8KqsvlsfuaT9kRSMUS8CfgpWj8JcJwijmeZhjR52k0UBpWLfn3JmRYW8xjZW6dlOSnS0yqwREPU7myyqUzhk1vyyUG7wLpk7uK9Bxmup0tnbnD4MeqDboAXlQYnIFVV+CXywlAQfHHCfQRsGhsEtu4excZVw7FD1rjnro9bcWFY9cm/KdDBxZCYQoT/UW0OBbipoINycrmfMKt1r4mGE9/MdVoIEMBc54aI6sb2g5J2GtNCYfEu+1/gA99xY0+5B3ydH74cbqfHYOZIvu11Q7GnpZ6l8zTLlMuF/pvlSily76I45H0YZ3HcdQnf/GoKC942P6fNsynHEX01zASYM8dzyMxHQpNEx7fcXGi+uiBUD/Xdm2jwzr9ZEP5eEVlrpcAvr8c9S5ylE50lwR+Mp3vaZxPoLdSGZrfyXy4v97UZSnYARQBacmn6KgsIHIOKhYOxNgUG0jwCO/zrPvlbjiYTHQYLOCcldTULvXOdn51enJFGVjscGoZfRj6vZgyHVCUW4iip4iSbSKPcPbf0GMZuniS9qJ3Wybve0/xpppdOv1c40ez0NKQyQkEZRb+V0qfesatJKZd/hUGr+MCAwEAAQ==";
    final byte bytePKCS[] = Base64.base64ToByteArray(pkcs);
    final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(bytePKCS);

    PublicKey pubKey = null;
    try {
        pubKey = KeyFactory.getInstance("RSA").generatePublic(pubKeySpec);
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }

    final String targetResultText = "NZqTzuNli92vuXEQNchGeF6faN/NBHykhfqBFcWzBHZhbgljZaWAcAzasFSm/odZZ6vBD2jK7J4oi5BmDjxNdEjkXyv3OZ2sOTLCfudgPwXcXmmhOwWHDLY02OX0X3RwBHzqWczqAd4dwslo59Gp5CT59GWXenJPL8wvG90WH2XAKOmHg5uEZj55ZvErRQ6StPVzLkiNCMPOhga7FZWK/rSEpT6BHDy3CibDZ0PNRtAW4wiYAr0Cw6brqiqkN301Bz6DzrV5380KDHkw26GjM8URSTFekwvZ7FISQ72UaNHhjnh1WgMIPf/QDbrEh5b+rmdZjzc5bdjyONrQuoj0rzrWLN4z8lsrBnKFVo+zVyUeqr0IxqD2aHDLyz5OE4fb5IZJHEMfYr/R79Zfe8IuQ2tusA02ZlFzGRGBhAkb0VygXxJxPXkjbkPaLbZQZOsKLUoIDkcbNoUTxeS9+4LWVg1j5q3HR9OSvmsF5I/SszvVrnXdNaz1IKCfVYkwpIBQ+Y+xI/K360dWIHR/vn7TU4UsGmWtwVciq0jWLuBN/qRE6MV47TDRQu63GzeV00yAM/xUM33qWNXCV1tbGXNZw8jHpakgflTY0hcjOFHPpq2UfJCyxiSBtZ0b7hw9Rvhi8VwYc243jXO9CvGq+J6JYvchvKHjq2+YKn1UB2+gs20=";
    final String plainText = "a";
    String resultText = "";
    try {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey, secureRandomWithFixSeed);
        final byte[] result = cipher.doFinal(plainText.getBytes());
        resultText = Base64.byteArrayToBase64(result);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    }
    assertThat(resultText, is(targetResultText));
}

ああ

4

3 に答える 3

0

理由がわかりました。

Android 4.4 でテスト ケースを実行すると動作しないことがわかりましたが、4.1.2では動作します。

さらに調査すると、Android は新しいバージョン (AndroidOpenSSL) で暗号化/説明に OpenSSL を使用しているようです。

ファイル内、external/conscrypt/src/main/java/org/conscrypt/OpenSSLCipherRSA.java

@Override
protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
    engineInitInternal(opmode, key);
}

ネイティブの OpenSSL ライブラリを使用して暗号化し、指定された SecureRandom を使用しないことを示しています。

解決策は、Cipher.getInstance() のときにプロバイダーを提供することです。

@Test
public void test_cipher() {
    private static final String PROVIDER_NAME = "BC";
    final Provider provider = Security.getProvider(PROVIDER_NAME);

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
}
于 2015-12-28T05:59:18.073 に答える
0

あなたがやろうとしていることをするべきではありません。2 つの暗号化された値を比較して同じかどうかを判断できるようにすることは、暗号化のポイントではありません。これを機能させることができると確信していますが、効果的に機能を無効にし、暗号化するすべてのものを同じように表示するために安全性を低下させます.

パスワードを解読せずに 2 つの値を比較できるようにしたい場合、本当に必要なのはハッシュ関数です。具体的には、少なくとも SHA1、または SHA-256 (Better) の使用を検討してください。

Javaでsha256を使用して文字列をハッシュする方法は?

設計上、ハッシュは一方向です (たとえば、Rainbow Tableのようなものがないとパスワードを元に戻すことはできません)。ただし、新しい値と古い値を比較して、説明どおりに使用するように設計されています。

本当に暗号化された値を使用したい場合は、パスワード値を復号化し、それを平文と比較する必要があります。ただし、ハッシュはベスト プラクティスに従います

于 2015-11-30T12:42:32.433 に答える