2

SJCL サーバー側で暗号化された文字列があり、利用可能なライブラリを使用して Android で復号化する必要があります。PBKDF2 からキーを生成できないという問題に遭遇するまで、BouncyCastle を試しました。現在、SpongyCastle を使用していますが、まだ問題が発生しています。キーを生成して文字列を復号化するためのこれまでのコードは次のとおりです。

private static byte[] decrypt(SecretKey key, byte[] encrypted, byte[] iv) throws Exception {
    IvParameterSpec ivSpec = new IvParameterSpec(iv);
    Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
    byte[] decrypted = cipher.doFinal(encrypted);
    return decrypted;
}

public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // Number of PBKDF2 hardening rounds to use. Larger values increase
    // computation time. You should select a value that causes computation
    // to take >100ms.
    final int iterations = 1000;

    // Generate a 128-bit key
    final int outputKeyLength = 128;

    /*SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
    SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);*/

    PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
    generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(passphraseOrPin), salt, iterations);
    KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(outputKeyLength);
    SecretKey secretKey = new SecretKeySpec(key.getKey(), "AES");
    return secretKey;
}

関数でそれを呼び出す方法は次のとおりです。

char[] key = * put PBKDF2 password here *;

// Generate key from password
    SecretKey decryptionKey = null;
    try {
        decryptionKey = generateKey(key, decodedObject.get("salt").getAsString().getBytes());
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }

    byte[] decryptedTicketBytes = null;

    // Decrypt the ticket
    try {
        decryptedTicketBytes = decrypt(decryptionKey, decodedObject.get("ct").getAsString().getBytes(), decodedObject.get("iv").getAsString().getBytes());
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }

decodedObject は、UTF-8 を使用して JsonParser を実行し、Base64 でデコードした後の SJCL からの文字列です。私はそれを受け取り、パスワードを使用してSJCL Demoを実行し、文字列を問題なく復号化しました。ここで単純なものが欠けているに違いありません。

私が得ているエラーは cipher.doFinal ステップにあり、次のとおりです。

java.security.InvalidKeyException: nonce must have length from 7 to 13 octets

SJCL が暗号にパディングを使用していないと思うので、getInstance で「AES/CCM/PKCS5Padding」を使用しようとしましたが、次のエラーが発生しました。

javax.crypto.NoSuchPaddingException: Only NoPadding can be used with AEAD modes.

TLDR: Android で SJCL 文字列を解読する最も簡単な方法を探しています。提案をいただければ幸いです。

ありがとう!

4

3 に答える 3

2

これは Java では行われませんが、実際には Android で行われます。私が望んでいた解決策ではないことはわかっていますが、機能し、解決策です。

WebView を使用して Android で SJCL を実行し、ファイルを復号化できます。WebView JavaScript が通信できるインターフェイスが必要です。

public static class JavaScriptInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    JavaScriptInterface(Context c) {
        mContext = c;
    }

    //This is the function that is callable from the Javascript.
    @JavascriptInterface
    public void doJavaStuff(String dycryptedData)
    {
        //Do what you want with the decrypted data
    }
}

そこから、SJCL でスクリプトを取得するメソッドを作成する必要があります。

public static String getSJCL() { return "<script>\n" + "SJCL_HERE" + "<script>\n";

次に、HTML を作成してコードを実行します。これはすべて .html ファイルと .script ファイルで実行できますが、キーと暗号化されたファイルを動的にする必要がありました。

 public static String getHtmlForDecrypting(String encryptedData, String key) {
    return "<html>\n" +
            "    <head>\n" +
                    getSJCL() +
            "        <script type=\"text/javascript\">\n" +
            "            function displaymessage()\n" +
            "            {\n" +
            "                var obj = " + encryptedData + ";\n" +
            "                var objString = JSON.stringify(obj);\n" +
            "                var data = sjcl.decrypt(\"" + key + "\", objString);\n" +
            "                JSInterface.doJavaStuff(data);\n" +
            "            }\n" +
            "        </script>\n" +
            "    </head>\n" +
            "    <body onload=\"displaymessage()\"></body>\n" +
            "</html>\n";
}

次に復号化メソッドを作成します。

private static WebView wv;

private static JavaScriptInterface JSInterface;

private static String key1 = "YOURKEY";

public static void decrypt(Context context, String data) {
    JSInterface = new JavaScriptInterface(context);
    wv = new WebView(context);
    wv.addJavascriptInterface(JSInterface, "JSInterface");
    wv.getSettings().setJavaScriptEnabled(true);

    wv.loadData(getHtmlForDecrypting(data, key1), "text/html", null);
}
于 2016-07-29T16:46:08.203 に答える
0

問題は、4 ワードを使用するデフォルトの sclj iv 番号では Java が機能しないことです。解決策は、3 つの単語で iv 値を生成するように sclj に指示することです。

aesEncrypt:function (pass,data) {
var param = { // Java does not accepts the default 4 word size
        iv: sjcl.random.randomWords(3, 0)
};
return sjcl.encrypt(pass,data,param);
}

暗号化されたメッセージとともに iv と salt の値を渡すことを忘れないでください。より小さい iv 番号を生成するように sclj に指示できない場合は、Java の実装を変更するか、16 バイトの iv をサポートするものを見つけようとする必要があります。

于 2014-10-06T15:32:46.477 に答える