Использование ключа DER из Java в mbedtls Diffie-Hellman

У меня есть приложение Java, которое создает ключи для обмена ключами Диффи-Хеллмана. Эти ключи генерируются, а открытый ключ экспортируется следующим образом:

/*
 * Alice creates her own DH key pair with 2048-bit key size
 */
System.out.println("ALICE: Generate DH keypair ...");
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(2048);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();

// Alice creates and initializes her DH KeyAgreement object
System.out.println("ALICE: Initialization ...");
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());

// Alice encodes her public key, and sends it over to Bob.
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

В alicePubKeyEnc содержится открытый ключ, который я отправляю своему приложению на C++. Насколько я понимаю, эти данные являются закодированным ключом DER для моих параметров DHE. С другой стороны, я пытаюсь использовать этот ключ с mbedtls следующим образом:

// An example DER (?) key from Java.
unsigned char buf[] = {
    0x30, 0x82, 0x02, 0x28, 0x30, 0x82, 0x01, 0x1b, 0x06, 0x09, 0x2a, 0x86,
    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x03, 0x01, 0x30, 0x82, 0x01, 0x0c, 0x02,
    0x82, 0x01, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b,
    0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
    0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79,
    0x8e, 0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
    0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d,
    0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
    0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6,
    0xf4, 0x06, 0xb7, 0xed, 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5,
    0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51,
    0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
    0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8,
    0xfd, 0x24, 0xcf, 0x5f, 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96,
    0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07,
    0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
    0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46,
    0x2e, 0x36, 0xce, 0x3b, 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03,
    0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0,
    0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
    0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18,
    0x98, 0xfa, 0x05, 0x10, 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x01, 0x02, 0x02,
    0x02, 0x04, 0x00, 0x03, 0x82, 0x01, 0x05, 0x00, 0x02, 0x82, 0x01, 0x00,
    0x2f, 0x6e, 0xa3, 0xd8, 0x5c, 0xca, 0x06, 0x99, 0xbd, 0x35, 0x90, 0xb5,
    0xc3, 0x11, 0xa6, 0x48, 0x5b, 0x5a, 0xe9, 0x14, 0xac, 0x4a, 0xed, 0x2d,
    0x46, 0xb1, 0x6b, 0xc7, 0x5b, 0x88, 0xc6, 0xa7, 0x51, 0x07, 0xa0, 0x4d,
    0x5f, 0xc0, 0x32, 0x54, 0x9d, 0x63, 0x35, 0xa2, 0x3b, 0x6a, 0x9a, 0x0a,
    0xb9, 0x46, 0xff, 0x0b, 0x78, 0x5d, 0xa7, 0x17, 0x94, 0x58, 0x28, 0x28,
    0xf2, 0xa0, 0xea, 0x3a, 0xf0, 0xe8, 0x8f, 0xc2, 0xa1, 0x7c, 0xb1, 0x50,
    0x38, 0xb7, 0x01, 0xe1, 0x69, 0x42, 0x30, 0x1e, 0x06, 0x06, 0x06, 0x17,
    0x46, 0xc8, 0x1f, 0xb1, 0xb4, 0xd2, 0xff, 0xf1, 0x32, 0xdc, 0xc2, 0xfc,
    0x2c, 0x15, 0xe4, 0xfe, 0xae, 0xb2, 0x1f, 0x8b, 0x20, 0x29, 0x87, 0xbe,
    0x31, 0x8c, 0xf2, 0x01, 0x95, 0x51, 0x35, 0x76, 0x4c, 0x83, 0xe4, 0x06,
    0x46, 0x96, 0x62, 0x42, 0x2f, 0x23, 0xb4, 0xb7, 0xc7, 0x41, 0x4b, 0x4e,
    0xf5, 0xab, 0x20, 0xb0, 0x45, 0x27, 0x52, 0x64, 0x63, 0x18, 0x87, 0x72,
    0xa7, 0x41, 0x80, 0xbd, 0x15, 0x4d, 0xa8, 0x48, 0x69, 0x69, 0x8b, 0x64,
    0x38, 0x03, 0xa7, 0x72, 0xf7, 0xeb, 0x2b, 0xdd, 0x19, 0x2d, 0x63, 0x3a,
    0xa6, 0x1b, 0x6f, 0xcc, 0x81, 0x14, 0xde, 0x29, 0xd9, 0x55, 0x66, 0xd1,
    0x95, 0x8d, 0x2f, 0x15, 0x5e, 0x29, 0xad, 0xf8, 0x82, 0xf0, 0x68, 0xac,
    0x65, 0xf7, 0x54, 0x4f, 0x3e, 0x52, 0x64, 0xe8, 0x28, 0x52, 0x0f, 0x7c,
    0xbe, 0xc4, 0xf2, 0x20, 0x40, 0x97, 0xfa, 0x0a, 0x78, 0x5b, 0x1d, 0xf8,
    0xdb, 0x15, 0x02, 0xbe, 0xc3, 0xf0, 0xb0, 0x3a, 0xda, 0x6a, 0xe6, 0x5f,
    0x74, 0x48, 0x74, 0x0e, 0xe9, 0x1d, 0x02, 0xda, 0x25, 0x37, 0x4f, 0x41,
    0x11, 0x63, 0x32, 0x93, 0x44, 0xfe, 0x5b, 0x3a, 0x7e, 0x25, 0xcc, 0x9f,
    0xd5, 0x99, 0x41, 0x9f, 0x00
};

size_t size = 557; // 556 + NULL terminating byte per the docs.

mbedtls_dhm_context ctx;
mbedtls_dhm_init(&ctx);
int res = mbedtls_dhm_parse_dhm(&ctx, buf, size);

if (res != 0) {
    printf("FAIL\n", -res);
}

res приводит к отрицательному ненулевому значению (0xffffcc1e). Я проверил коды ошибок для синтаксического анализа x509 в mbedtls, но не могу найти соответствующий код ошибки.

Любая идея, почему я не могу загрузить этот сертификат?

Обновить

Я обновил свой код C, чтобы распечатать соответствующее сообщение об ошибке для mbedtls:

0x0000023c4f9fb2b0 "DHM - The ASN.1 data is not formatted correctly : ASN1 - ASN1 tag was of an unexpected value"

So I took the hex values ​​from my key and ran it through http://lapo.it/asn1js/#308202283082011B06092A864886F70D0103013082010C0282010100FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF020102020204000382010500028201002F6EA3D85CCA0699BD3590B5C311A6485B5AE914AC4AED2D46B16BC75B88C6A75107A04D5FC032549D6335A23B6A9A0AB946FF0B785DA71794582828F2A0EA3AF0E88FC2A17CB15038B701E16942301E0606061746C81FB1B4D2FFF132DCC2FC2C15E4FEAEB21F8B202987BE318CF201955135764C83E406469662422F23B4B7C7414B4EF5AB20B04527526463188772A74180BD154DA84869698B643803A772F7EB2BDD192D633AA61B6FCC8114DE29D95566D1958D2F155E29ADF882F068AC65F7544F3E5264E828520F7CBEC4F2204097FA0A785B1DF8DB1502BEC3F0B03ADA6AE65F7448740EE91D02DA25374F411163329344FE5B3A7E25CC9FD599419F (‹-- That links the the actual output from the key) which indicates some structure to my key and seems< /em>, чтобы нормально разобрать ключ. Возможно, это проблема с тем, как я передаю ключ в mbedtls?


person Julio    schedule 12.04.2018    source источник
comment
size_t size = 557; =› size_t size = sizeof buf;. Зачем тегировать так много языка? Я не понял, какой код вызывает у вас проблемы.   -  person Stargateur    schedule 15.04.2018
comment
Я пометил его как C++, так и Java, потому что открытый ключ экспортируется из java и используется в C++. Я не уверен, в чем проблема, но подозреваю, что открытый ключ генерируется в Java. Я думаю, что это может быть не то, что я думаю (закодированный открытый ключ). Если я сгенерирую ключ с помощью OpenSSL, код mbed (c++), похоже, будет работать нормально... проблема заключается только в ключе java.   -  person Julio    schedule 15.04.2018


Ответы (1)


Вы передаете неверную информацию в mbed TLS mbedtls_dhm_parse_dhm. Эта функция ожидает закодированные в DER (или PEM) параметры DH, а не ключ.

Использование BouncyCastle DHParameter вы можете получить параметры в кодировке DER следующим образом:

DHParameterSpec dhParams = ((DHPublicKey) aliceKeyPair.getPublic()).getParams();
DHParameter dhP = new DHParameter(dhParams.getP(), dhParams.getG(), 0);
byte[] encodedParams = dhP.getEncoded(ASN1Encodable.DER);

Это даст вам байты, которые вы затем можете передать в mbedtls_dhm_parse_dhm, либо в виде необработанных байтов, как вы делаете сейчас, либо в кодировке PEM, поскольку эта функция также примет это. Обратите внимание, что я передаю 0 для L, так как mbed TLS все равно отбрасывает его. Также обратите внимание, что getEncoded вызывает исключение, поэтому обязательно обработайте исключение.

Шаги для завершения обмена ключами:

В Java:

KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(2048);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());
DHParameterSpec dhParams = ((DHPublicKey) aliceKpair.getPublic()).getParams();
DHParameter dhP = new DHParameter(dhParams.getP(), dhParams.getG(), 0);
byte[] encodedParams = dhP.getEncoded(ASN1Encodable.DER);
byte[] javaPub = ((DHPublicKey)aliceKeyPair.getPublic()).getY().toByteArray();

Затем в С++:

mbedtls_dhm_context ctx;
mbedtls_dhm_init(&ctx);
...
mbedtls_dhm_parse_dhm(&ctx, encodedParams, encodedParamsLen);
...
uint_8t mbedtlspub[128];
mbedtls_dhm_make_public(&ctx, 128, mbedtlspub, sizeof(mbedtlspub), mbedtls_ctr_drbg_random, &rnd_info);
...
mbedtls_dhm_read_public(&ctx, javaPub, javaPubLen);
...
uint_8t mbedtlssecret[128];
mbedtls_dhm_calc_secret(&ctx, mbedtlssecret, (size_t)secret_len, &olen, mbedtls_ctr_drbg_random, &rnd_info);

И вернемся к Java (при условии, что вы закодировали mbedtlspub из предыдущих шагов в Base64, но вы можете сделать это, как хотите):

byte[] yBinary = Base64.decodeBase64(mbedtlspub.getBytes()); 
BigInteger y = new BigInteger(yBinary); 
DHPublicKeySpec dhPublicKeySpec = new DHPublicKeySpec(y, dhParams.getP(), dhParams.getG()); 
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); 
DHPublicKey mbedtlsPubKey = (DHPublicKey) KeyFactory.generatePublic(dhPublicKeySpec);
aliceKeyAgree.doPhase(mbedtlsPubKey, true);
byte[] javaSecretKey = aliceKeyAgree.generateSecret();

На этом обмен ключами завершен, и в этот момент mbedtlssecret и javaSecretKey должны совпадать. Таким образом, данные, передаваемые руками, это encodedParams и javaPub (из Java) и mbedtlspub (из C++). Я опустил некоторые детали, чтобы сосредоточиться на основных шагах. Также обратите внимание, что многие из этих функций либо возвращают код ошибки, либо бросают вызов, поэтому будьте осторожны при их использовании.

person mnistic    schedule 15.04.2018
comment
Спасибо, это имеет смысл. Включает ли это также значение открытого ключа из Java? Я вижу getP() и getG(); разве это не просто праймер и генератор? Как насчет закодированного открытого ключа, Y, я думаю? - person Julio; 15.04.2018
comment
Правильно, последовательность mbedtls такова: mbedtls_dhm_parse_dhm для инициализации контекста, затем mbedtls_dhm_make_public для создания собственного открытого ключа после инициализации с параметрами, затем mbedtls_dhm_read_public для выполнения обмена ключами. Данные, поступающие в mbedtls_dhm_read_public, вы можете получить с помощью ((DHPublicKey)aliceKeyPair.getPublic()).getY() - person mnistic; 15.04.2018
comment
Итак, я смог установить открытый ключ с помощью mbedtls_dhm_read_public и getY() из Java. Как мне сделать обратное и установить открытый ключ из mbedtls в Java? - person Julio; 16.04.2018
comment
@Julio Я отредактировал ответ, включив в него шаги по обмену ключами. Надеюсь, поможет! - person mnistic; 16.04.2018
comment
У меня не совсем получилось. Но вы определенно поставили меня на правильный путь. Спасибо за вашу помощь! - person Julio; 16.04.2018