1/* 2 * RTMP Diffie-Hellmann utilities 3 * Copyright (c) 2009 Andrej Stepanchuk 4 * Copyright (c) 2009-2010 Howard Chu 5 * Copyright (c) 2012 Samuel Pitoiset 6 * 7 * This file is part of FFmpeg. 8 * 9 * FFmpeg is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * FFmpeg is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with FFmpeg; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24/** 25 * @file 26 * RTMP Diffie-Hellmann utilities 27 */ 28 29#include <stdint.h> 30#include <string.h> 31 32#include "config.h" 33 34#include "libavutil/attributes.h" 35#include "libavutil/error.h" 36#include "libavutil/mem.h" 37#include "libavutil/random_seed.h" 38 39#include "rtmpdh.h" 40 41#if CONFIG_MBEDTLS 42#include <mbedtls/ctr_drbg.h> 43#include <mbedtls/entropy.h> 44#endif 45 46#define P1024 \ 47 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 48 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 49 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 50 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 51 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \ 52 "FFFFFFFFFFFFFFFF" 53 54#define Q1024 \ 55 "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \ 56 "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \ 57 "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \ 58 "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \ 59 "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \ 60 "FFFFFFFFFFFFFFFF" 61 62#if CONFIG_GMP 63#define bn_new(bn) \ 64 do { \ 65 bn = av_malloc(sizeof(*bn)); \ 66 if (bn) \ 67 mpz_init2(bn, 1); \ 68 } while (0) 69#define bn_free(bn) \ 70 do { \ 71 mpz_clear(bn); \ 72 av_free(bn); \ 73 } while (0) 74#define bn_set_word(bn, w) mpz_set_ui(bn, w) 75#define bn_cmp(a, b) mpz_cmp(a, b) 76#define bn_copy(to, from) mpz_set(to, from) 77#define bn_sub_word(bn, w) mpz_sub_ui(bn, bn, w) 78#define bn_cmp_1(bn) mpz_cmp_ui(bn, 1) 79#define bn_num_bytes(bn) (mpz_sizeinbase(bn, 2) + 7) / 8 80#define bn_bn2bin(bn, buf, len) \ 81 do { \ 82 memset(buf, 0, len); \ 83 if (bn_num_bytes(bn) <= len) \ 84 mpz_export(buf, NULL, 1, 1, 0, 0, bn); \ 85 } while (0) 86#define bn_bin2bn(bn, buf, len) \ 87 do { \ 88 bn_new(bn); \ 89 if (bn) \ 90 mpz_import(bn, len, 1, 1, 0, 0, buf); \ 91 } while (0) 92#define bn_hex2bn(bn, buf, ret) \ 93 do { \ 94 bn_new(bn); \ 95 if (bn) \ 96 ret = (mpz_set_str(bn, buf, 16) == 0); \ 97 else \ 98 ret = 1; \ 99 } while (0) 100#define bn_random(bn, num_bits) \ 101 do { \ 102 int bits = num_bits; \ 103 mpz_set_ui(bn, 0); \ 104 for (bits = num_bits; bits > 0; bits -= 32) { \ 105 mpz_mul_2exp(bn, bn, 32); \ 106 mpz_add_ui(bn, bn, av_get_random_seed()); \ 107 } \ 108 mpz_fdiv_r_2exp(bn, bn, num_bits); \ 109 } while (0) 110static int bn_modexp(FFBigNum bn, FFBigNum y, FFBigNum q, FFBigNum p) 111{ 112 mpz_powm(bn, y, q, p); 113 return 0; 114} 115#elif CONFIG_GCRYPT 116#define bn_new(bn) \ 117 do { \ 118 if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { \ 119 if (!gcry_check_version("1.5.4")) \ 120 return AVERROR(EINVAL); \ 121 gcry_control(GCRYCTL_DISABLE_SECMEM, 0); \ 122 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); \ 123 } \ 124 bn = gcry_mpi_new(1); \ 125 } while (0) 126#define bn_free(bn) gcry_mpi_release(bn) 127#define bn_set_word(bn, w) gcry_mpi_set_ui(bn, w) 128#define bn_cmp(a, b) gcry_mpi_cmp(a, b) 129#define bn_copy(to, from) gcry_mpi_set(to, from) 130#define bn_sub_word(bn, w) gcry_mpi_sub_ui(bn, bn, w) 131#define bn_cmp_1(bn) gcry_mpi_cmp_ui(bn, 1) 132#define bn_num_bytes(bn) (gcry_mpi_get_nbits(bn) + 7) / 8 133#define bn_bn2bin(bn, buf, len) gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn) 134#define bn_bin2bn(bn, buf, len) gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL) 135#define bn_hex2bn(bn, buf, ret) ret = (gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) == 0) 136#define bn_random(bn, num_bits) gcry_mpi_randomize(bn, num_bits, GCRY_WEAK_RANDOM) 137static int bn_modexp(FFBigNum bn, FFBigNum y, FFBigNum q, FFBigNum p) 138{ 139 gcry_mpi_powm(bn, y, q, p); 140 return 0; 141} 142#elif CONFIG_OPENSSL 143#define bn_new(bn) bn = BN_new() 144#define bn_free(bn) BN_free(bn) 145#define bn_set_word(bn, w) BN_set_word(bn, w) 146#define bn_cmp(a, b) BN_cmp(a, b) 147#define bn_copy(to, from) BN_copy(to, from) 148#define bn_sub_word(bn, w) BN_sub_word(bn, w) 149#define bn_cmp_1(bn) BN_cmp(bn, BN_value_one()) 150#define bn_num_bytes(bn) BN_num_bytes(bn) 151#define bn_bn2bin(bn, buf, len) BN_bn2bin(bn, buf) 152#define bn_bin2bn(bn, buf, len) bn = BN_bin2bn(buf, len, 0) 153#define bn_hex2bn(bn, buf, ret) ret = BN_hex2bn(&bn, buf) 154#define bn_random(bn, num_bits) BN_rand(bn, num_bits, 0, 0) 155static int bn_modexp(FFBigNum bn, FFBigNum y, FFBigNum q, FFBigNum p) 156{ 157 BN_CTX *ctx = BN_CTX_new(); 158 if (!ctx) 159 return AVERROR(ENOMEM); 160 if (!BN_mod_exp(bn, y, q, p, ctx)) { 161 BN_CTX_free(ctx); 162 return AVERROR(EINVAL); 163 } 164 BN_CTX_free(ctx); 165 return 0; 166} 167#elif CONFIG_MBEDTLS 168#define bn_new(bn) \ 169 do { \ 170 bn = av_malloc(sizeof(*bn)); \ 171 if (bn) \ 172 mbedtls_mpi_init(bn); \ 173 } while (0) 174#define bn_free(bn) \ 175 do { \ 176 mbedtls_mpi_free(bn); \ 177 av_free(bn); \ 178 } while (0) 179#define bn_set_word(bn, w) mbedtls_mpi_lset(bn, w) 180#define bn_cmp(a, b) mbedtls_mpi_cmp_mpi(a, b) 181#define bn_copy(to, from) mbedtls_mpi_copy(to, from) 182#define bn_sub_word(bn, w) mbedtls_mpi_sub_int(bn, bn, w) 183#define bn_cmp_1(bn) mbedtls_mpi_cmp_int(bn, 1) 184#define bn_num_bytes(bn) (mbedtls_mpi_bitlen(bn) + 7) / 8 185#define bn_bn2bin(bn, buf, len) mbedtls_mpi_write_binary(bn, buf, len) 186#define bn_bin2bn(bn, buf, len) \ 187 do { \ 188 bn_new(bn); \ 189 if (bn) \ 190 mbedtls_mpi_read_binary(bn, buf, len); \ 191 } while (0) 192#define bn_hex2bn(bn, buf, ret) \ 193 do { \ 194 bn_new(bn); \ 195 if (bn) \ 196 ret = (mbedtls_mpi_read_string(bn, 16, buf) == 0); \ 197 else \ 198 ret = 1; \ 199 } while (0) 200#define bn_random(bn, num_bits) \ 201 do { \ 202 mbedtls_entropy_context entropy_ctx; \ 203 mbedtls_ctr_drbg_context ctr_drbg_ctx; \ 204 \ 205 mbedtls_entropy_init(&entropy_ctx); \ 206 mbedtls_ctr_drbg_init(&ctr_drbg_ctx); \ 207 mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, \ 208 mbedtls_entropy_func, \ 209 &entropy_ctx, \ 210 NULL, 0); \ 211 mbedtls_mpi_fill_random(bn, (num_bits + 7) / 8, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); \ 212 mbedtls_ctr_drbg_free(&ctr_drbg_ctx); \ 213 mbedtls_entropy_free(&entropy_ctx); \ 214 } while (0) 215#define bn_modexp(bn, y, q, p) mbedtls_mpi_exp_mod(bn, y, q, p, 0) 216 217#endif 218 219#define MAX_BYTES 18000 220 221#define dh_new() av_mallocz(sizeof(FF_DH)) 222 223static FFBigNum dh_generate_key(FF_DH *dh) 224{ 225 int num_bytes; 226 227 num_bytes = bn_num_bytes(dh->p) - 1; 228 if (num_bytes <= 0 || num_bytes > MAX_BYTES) 229 return NULL; 230 231 bn_new(dh->priv_key); 232 if (!dh->priv_key) 233 return NULL; 234 bn_random(dh->priv_key, 8 * num_bytes); 235 236 bn_new(dh->pub_key); 237 if (!dh->pub_key) { 238 bn_free(dh->priv_key); 239 return NULL; 240 } 241 242 if (bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p) < 0) 243 return NULL; 244 245 return dh->pub_key; 246} 247 248static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn, 249 uint32_t secret_key_len, uint8_t *secret_key) 250{ 251 FFBigNum k; 252 int ret; 253 254 bn_new(k); 255 if (!k) 256 return -1; 257 258 if ((ret = bn_modexp(k, pub_key_bn, dh->priv_key, dh->p)) < 0) { 259 bn_free(k); 260 return ret; 261 } 262 bn_bn2bin(k, secret_key, secret_key_len); 263 bn_free(k); 264 265 /* return the length of the shared secret key like DH_compute_key */ 266 return secret_key_len; 267} 268 269void ff_dh_free(FF_DH *dh) 270{ 271 if (!dh) 272 return; 273 bn_free(dh->p); 274 bn_free(dh->g); 275 bn_free(dh->pub_key); 276 bn_free(dh->priv_key); 277 av_free(dh); 278} 279 280static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q) 281{ 282 FFBigNum bn = NULL; 283 int ret = AVERROR(EINVAL); 284 285 bn_new(bn); 286 if (!bn) 287 return AVERROR(ENOMEM); 288 289 /* y must lie in [2, p - 1] */ 290 bn_set_word(bn, 1); 291 if (!bn_cmp(y, bn)) 292 goto fail; 293 294 /* bn = p - 2 */ 295 bn_copy(bn, p); 296 bn_sub_word(bn, 1); 297 if (!bn_cmp(y, bn)) 298 goto fail; 299 300 /* Verify with Sophie-Germain prime 301 * 302 * This is a nice test to make sure the public key position is calculated 303 * correctly. This test will fail in about 50% of the cases if applied to 304 * random data. 305 */ 306 /* y must fulfill y^q mod p = 1 */ 307 if ((ret = bn_modexp(bn, y, q, p)) < 0) 308 goto fail; 309 310 ret = AVERROR(EINVAL); 311 if (bn_cmp_1(bn)) 312 goto fail; 313 314 ret = 0; 315fail: 316 bn_free(bn); 317 318 return ret; 319} 320 321av_cold FF_DH *ff_dh_init(int key_len) 322{ 323 FF_DH *dh; 324 int ret; 325 326 if (!(dh = dh_new())) 327 return NULL; 328 329 bn_new(dh->g); 330 if (!dh->g) 331 goto fail; 332 333 bn_hex2bn(dh->p, P1024, ret); 334 if (!ret) 335 goto fail; 336 337 bn_set_word(dh->g, 2); 338 dh->length = key_len; 339 340 return dh; 341 342fail: 343 ff_dh_free(dh); 344 345 return NULL; 346} 347 348int ff_dh_generate_public_key(FF_DH *dh) 349{ 350 int ret = 0; 351 352 while (!ret) { 353 FFBigNum q1 = NULL; 354 355 if (!dh_generate_key(dh)) 356 return AVERROR(EINVAL); 357 358 bn_hex2bn(q1, Q1024, ret); 359 if (!ret) 360 return AVERROR(ENOMEM); 361 362 ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1); 363 bn_free(q1); 364 365 if (!ret) { 366 /* the public key is valid */ 367 break; 368 } 369 } 370 371 return ret; 372} 373 374int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len) 375{ 376 int len; 377 378 /* compute the length of the public key */ 379 len = bn_num_bytes(dh->pub_key); 380 if (len <= 0 || len > pub_key_len) 381 return AVERROR(EINVAL); 382 383 /* convert the public key value into big-endian form */ 384 memset(pub_key, 0, pub_key_len); 385 bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len); 386 387 return 0; 388} 389 390int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key, 391 int pub_key_len, uint8_t *secret_key, 392 int secret_key_len) 393{ 394 FFBigNum q1 = NULL, pub_key_bn = NULL; 395 int ret; 396 397 /* convert the big-endian form of the public key into a bignum */ 398 bn_bin2bn(pub_key_bn, pub_key, pub_key_len); 399 if (!pub_key_bn) 400 return AVERROR(ENOMEM); 401 402 /* convert the string containing a hexadecimal number into a bignum */ 403 bn_hex2bn(q1, Q1024, ret); 404 if (!ret) { 405 ret = AVERROR(ENOMEM); 406 goto fail; 407 } 408 409 /* when the public key is valid we have to compute the shared secret key */ 410 if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) { 411 goto fail; 412 } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len, 413 secret_key)) < 0) { 414 ret = AVERROR(EINVAL); 415 goto fail; 416 } 417 418fail: 419 bn_free(pub_key_bn); 420 bn_free(q1); 421 422 return ret; 423} 424