Как десериализовать публичные c / частные ключи P-384 в Android? - PullRequest
2 голосов
/ 15 февраля 2020

У меня есть набор открытых / закрытых ключей, созданный с помощью sjcl. js в node.js с использованием кривой P-384. Он построен следующим образом:

var keyPair = sjcl.ecc.elGamal.generateKeys(sjcl.ecc.curves.c384);

var pubGet = keyPair.pub.get();
var secGet = keyPair.sec.get();

var pub = sjcl.codec.base64.fromBits(pubGet.x.concat(pubGet.y));
var pubKey = "JjcqsHEy9dv8uHQzAoH7do6veTwtK3sxlwB1f/F4PvRXqi36/DCioEaEQu265xtBZ5MQ+SSVlBAaGfLi0NJHe41klrPivyyjATBmE2ZE7tb+Zb0SJhIvL4By89VCVfH/"

var sec = sjcl.codec.base64.fromBits(secGet);
var secKey = "8DDr+bZTVHyC5yLNEpVfSCekNJUTq3S8oibzdS5mp/55bDHgW7Dtkl3D4+naV8Ul"

В Javascript это может быть использовано для шифрования строки "hello world", например:

var teststring = "hello world"
sjcl.encrypt(teststring, pub)

, что приводит к объектам шифрования с соответствующими параметрами:

"{\"iv\":\"TEcjccaUsKWzg+UwRxIAtg==\",\"v\":1,\"iter\":10000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"jNHR3i4TJ44=\",\"ct\":\"9p5DCV6AdPFsUYuXqLvELg/pJd1ShesQLOgRkrzQmZUdo7Idfu8I9B74wl5A7CfVG08vbG6Etr6VetrPdQpO/GKWOvN9eisaHeKrOHgBAGLx0GP+Mh3OVX/JtDvr0/F5DK1FRyFLkZ6IPxRn9I+s7UjXQ3HPazPNEVdHuA2Jgi/49jPkFZ0dSQ==\"}"

Опять же, в Javascript ключи могут быть десерализованы следующим образом: и в javascript ключ может быть десериализован следующим образом

var privateKeyObject = new sjcl.ecc.elGamal.secretKey(
    sjcl.ecc.curves.c384,
    sjcl.ecc.curves.c384.field.fromBits(sjcl.codec.base64.toBits(privateKey))
  );

и используется для расшифровки

var cleartext = sjcl.decrypt(privateKeyObject, message);

До этого момента все прекрасно работает. Однако теперь мне необходимо выполнить ту же операцию в Android, используя Kotlin.

var pubKey = "JjcqsHEy9dv8uHQzAoH7do6veTwtK3sxlwB1f/F4PvRXqi36/DCioEaEQu265xtBZ5MQ+SSVlBAaGfLi0NJHe41klrPivyyjATBmE2ZE7tb+Zb0SJhIvL4By89VCVfH/"
var secKey = "8DDr+bZTVHyC5yLNEpVfSCekNJUTq3S8oibzdS5mp/55bDHgW7Dtkl3D4+naV8Ul"
var teststring = "hello world"

 // deserialize base64 private key into object
 val input = secKey
 val encoded = Base64.getDecoder().decode(input);
 val aesPrivKey = SecretKeySpec(encoded, "P-384");

// this is the same object as created above in the browser with Javascript
val encodedJSONNew = "{\n" +
            "  \"iv\":\"TEcjccaUsKWzg+UwRxIAtg==\",\n" +
            "  \"v\":1,\n" +
            "  \"iter\":10000,\n" +
            "  \"ks\":128,\n" +
            "  \"ts\":64,\n" +
            "  \"mode\":\"ccm\",\n" +
            "  \"adata\":\"\",\n" +
            "  \"cipher\":\"aes\",\n" +
            "  \"salt\":\"jNHR3i4TJ44=\",\n" +
            "  \"ct\":\"9p5DCV6AdPFsUYuXqLvELg/pJd1ShesQLOgRkrzQmZUdo7Idfu8I9B74wl5A7CfVG08vbG6Etr6VetrPdQpO/GKWOvN9eisaHeKrOHgBAGLx0GP+Mh3OVX/JtDvr0/F5DK1FRyFLkZ6IPxRn9I+s7UjXQ3HPazPNEVdHuA2Jgi/49jPkFZ0dSQ==\"\n" +
            "}"

    //sjcl.encrypt(teststring, pub)

    // Decode the encoded JSON and create a JSON Object from it
    val jsonn = JSONObject((encodedJSONNew))

    // We need the salt, the IV and the cipher text;
    // all of them need to be Base64 decoded
    val saltNew = d.decode(jsonn.getString("salt"))
    var ivNew = d.decode(jsonn.getString("iv"))
    val cipherTextNew = d.decode(jsonn.getString("ct"))

    // Also, we need the keySize and the iteration count
    val keySizeNew = jsonn.getInt("ks")
    val iterationsNew = jsonn.getInt("iter")

    // Now, SJCL doesn't use the whole IV in CCM mode;
    lolNew = 2

    // Cut the IV to the appropriate length, which is 15 - L
    ivNew = Arrays.copyOf(ivNew, 15-lolNew)
    println("iv: " + Base64.getEncoder().encodeToString(ivNew))

    // Crypto stuff.
    // First, we need the secret AES key,
    // which is generated from password and salt
    val factoryNew = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")

    val specNew = PBEKeySpec(secKey.toCharArray(), saltNew, iterationsNew, keySizeNew)

    val tmpNew = factoryNew.generateSecret(specNew)
    val secretNew = SecretKeySpec(tmpNew.getEncoded(), "AES")

    // Now it's time to decrypt.
    val cipherNew = Cipher.getInstance("AES/CCM/NoPadding",
        BouncyCastleProvider()
    )

    // change here to use serialized priv key and iv
    cipherNew.init(Cipher.DECRYPT_MODE, aesPrivKey, IvParameterSpec(ivNew));

    val finalStringNew = String(cipherNew.doFinal(cipherTextNew));
    println("decryption successful: " + finalStringNew)

Произошла следующая ошибка:

Caused by: java.lang.IllegalArgumentException: Key length not 128/192/256 bits.

Как правильно десериализовать этот ключ в Android и заставить его работать?

1 Ответ

1 голос
/ 24 февраля 2020

Поскольку разработка этого ответа для вас занимает очень много времени, и я могу рассказать вам, что бы я делал на вашем месте.

Посмотрите на этот исходный код и попытайтесь выяснить, что делает эта библиотека сделайте http://bitwiseshiftleft.github.io/sjcl/doc/sjcl.js.html и сделайте это в bouncycastle.

Извините, приятель, но это ваша единственная ставка, если она вам не нравится, попробуйте использовать другую библиотеку.

...