LCOV - code coverage report
Current view: top level - journal - fsprg.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 221 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 22 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /*
       4             :  * fsprg v0.1  -  (seekable) forward-secure pseudorandom generator
       5             :  * Copyright (C) 2012 B. Poettering
       6             :  * Contact: fsprg@point-at-infinity.org
       7             :  *
       8             :  * This library is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with this library; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :  * 02110-1301  USA
      22             :  */
      23             : 
      24             : /*
      25             :  * See "Practical Secure Logging: Seekable Sequential Key Generators"
      26             :  * by G. A. Marson, B. Poettering for details:
      27             :  *
      28             :  * http://eprint.iacr.org/2013/397
      29             :  */
      30             : 
      31             : #include <gcrypt.h>
      32             : #include <string.h>
      33             : 
      34             : #include "fsprg.h"
      35             : 
      36             : #define ISVALID_SECPAR(secpar) (((secpar) % 16 == 0) && ((secpar) >= 16) && ((secpar) <= 16384))
      37             : #define VALIDATE_SECPAR(secpar) assert(ISVALID_SECPAR(secpar));
      38             : 
      39             : #define RND_HASH GCRY_MD_SHA256
      40             : #define RND_GEN_P 0x01
      41             : #define RND_GEN_Q 0x02
      42             : #define RND_GEN_X 0x03
      43             : 
      44             : /******************************************************************************/
      45             : 
      46           0 : static void mpi_export(void *buf, size_t buflen, const gcry_mpi_t x) {
      47             :         unsigned len;
      48             :         size_t nwritten;
      49             : 
      50           0 :         assert(gcry_mpi_cmp_ui(x, 0) >= 0);
      51           0 :         len = (gcry_mpi_get_nbits(x) + 7) / 8;
      52           0 :         assert(len <= buflen);
      53           0 :         memzero(buf, buflen);
      54           0 :         gcry_mpi_print(GCRYMPI_FMT_USG, buf + (buflen - len), len, &nwritten, x);
      55           0 :         assert(nwritten == len);
      56           0 : }
      57             : 
      58           0 : static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
      59             :         gcry_mpi_t h;
      60             :         unsigned len;
      61             : 
      62           0 :         gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL);
      63           0 :         len = (gcry_mpi_get_nbits(h) + 7) / 8;
      64           0 :         assert(len <= buflen);
      65           0 :         assert(gcry_mpi_cmp_ui(h, 0) >= 0);
      66             : 
      67           0 :         return h;
      68             : }
      69             : 
      70           0 : static void uint64_export(void *buf, size_t buflen, uint64_t x) {
      71           0 :         assert(buflen == 8);
      72           0 :         ((uint8_t*) buf)[0] = (x >> 56) & 0xff;
      73           0 :         ((uint8_t*) buf)[1] = (x >> 48) & 0xff;
      74           0 :         ((uint8_t*) buf)[2] = (x >> 40) & 0xff;
      75           0 :         ((uint8_t*) buf)[3] = (x >> 32) & 0xff;
      76           0 :         ((uint8_t*) buf)[4] = (x >> 24) & 0xff;
      77           0 :         ((uint8_t*) buf)[5] = (x >> 16) & 0xff;
      78           0 :         ((uint8_t*) buf)[6] = (x >>  8) & 0xff;
      79           0 :         ((uint8_t*) buf)[7] = (x >>  0) & 0xff;
      80           0 : }
      81             : 
      82           0 : _pure_ static uint64_t uint64_import(const void *buf, size_t buflen) {
      83           0 :         assert(buflen == 8);
      84             :         return
      85           0 :                 (uint64_t)(((uint8_t*) buf)[0]) << 56 |
      86           0 :                 (uint64_t)(((uint8_t*) buf)[1]) << 48 |
      87           0 :                 (uint64_t)(((uint8_t*) buf)[2]) << 40 |
      88           0 :                 (uint64_t)(((uint8_t*) buf)[3]) << 32 |
      89           0 :                 (uint64_t)(((uint8_t*) buf)[4]) << 24 |
      90           0 :                 (uint64_t)(((uint8_t*) buf)[5]) << 16 |
      91           0 :                 (uint64_t)(((uint8_t*) buf)[6]) <<  8 |
      92           0 :                 (uint64_t)(((uint8_t*) buf)[7]) <<  0;
      93             : }
      94             : 
      95             : /* deterministically generate from seed/idx a string of buflen pseudorandom bytes */
      96           0 : static void det_randomize(void *buf, size_t buflen, const void *seed, size_t seedlen, uint32_t idx) {
      97             :         gcry_md_hd_t hd, hd2;
      98             :         size_t olen, cpylen;
      99             :         uint32_t ctr;
     100             : 
     101           0 :         olen = gcry_md_get_algo_dlen(RND_HASH);
     102           0 :         gcry_md_open(&hd, RND_HASH, 0);
     103           0 :         gcry_md_write(hd, seed, seedlen);
     104           0 :         gcry_md_putc(hd, (idx >> 24) & 0xff);
     105           0 :         gcry_md_putc(hd, (idx >> 16) & 0xff);
     106           0 :         gcry_md_putc(hd, (idx >>  8) & 0xff);
     107           0 :         gcry_md_putc(hd, (idx >>  0) & 0xff);
     108             : 
     109           0 :         for (ctr = 0; buflen; ctr++) {
     110           0 :                 gcry_md_copy(&hd2, hd);
     111           0 :                 gcry_md_putc(hd2, (ctr >> 24) & 0xff);
     112           0 :                 gcry_md_putc(hd2, (ctr >> 16) & 0xff);
     113           0 :                 gcry_md_putc(hd2, (ctr >>  8) & 0xff);
     114           0 :                 gcry_md_putc(hd2, (ctr >>  0) & 0xff);
     115           0 :                 gcry_md_final(hd2);
     116           0 :                 cpylen = (buflen < olen) ? buflen : olen;
     117           0 :                 memcpy(buf, gcry_md_read(hd2, RND_HASH), cpylen);
     118           0 :                 gcry_md_close(hd2);
     119           0 :                 buf += cpylen;
     120           0 :                 buflen -= cpylen;
     121             :         }
     122           0 :         gcry_md_close(hd);
     123           0 : }
     124             : 
     125             : /* deterministically generate from seed/idx a prime of length `bits' that is 3 (mod 4) */
     126           0 : static gcry_mpi_t genprime3mod4(int bits, const void *seed, size_t seedlen, uint32_t idx) {
     127           0 :         size_t buflen = bits / 8;
     128           0 :         uint8_t buf[buflen];
     129             :         gcry_mpi_t p;
     130             : 
     131           0 :         assert(bits % 8 == 0);
     132           0 :         assert(buflen > 0);
     133             : 
     134           0 :         det_randomize(buf, buflen, seed, seedlen, idx);
     135           0 :         buf[0] |= 0xc0; /* set upper two bits, so that n=pq has maximum size */
     136           0 :         buf[buflen - 1] |= 0x03; /* set lower two bits, to have result 3 (mod 4) */
     137             : 
     138           0 :         p = mpi_import(buf, buflen);
     139           0 :         while (gcry_prime_check(p, 0))
     140           0 :                 gcry_mpi_add_ui(p, p, 4);
     141             : 
     142           0 :         return p;
     143             : }
     144             : 
     145             : /* deterministically generate from seed/idx a quadratic residue (mod n) */
     146           0 : static gcry_mpi_t gensquare(const gcry_mpi_t n, const void *seed, size_t seedlen, uint32_t idx, unsigned secpar) {
     147           0 :         size_t buflen = secpar / 8;
     148           0 :         uint8_t buf[buflen];
     149             :         gcry_mpi_t x;
     150             : 
     151           0 :         det_randomize(buf, buflen, seed, seedlen, idx);
     152           0 :         buf[0] &= 0x7f; /* clear upper bit, so that we have x < n */
     153           0 :         x = mpi_import(buf, buflen);
     154           0 :         assert(gcry_mpi_cmp(x, n) < 0);
     155           0 :         gcry_mpi_mulm(x, x, x, n);
     156           0 :         return x;
     157             : }
     158             : 
     159             : /* compute 2^m (mod phi(p)), for a prime p */
     160           0 : static gcry_mpi_t twopowmodphi(uint64_t m, const gcry_mpi_t p) {
     161             :         gcry_mpi_t phi, r;
     162             :         int n;
     163             : 
     164           0 :         phi = gcry_mpi_new(0);
     165           0 :         gcry_mpi_sub_ui(phi, p, 1);
     166             : 
     167             :         /* count number of used bits in m */
     168           0 :         for (n = 0; (1ULL << n) <= m; n++)
     169             :                 ;
     170             : 
     171           0 :         r = gcry_mpi_new(0);
     172           0 :         gcry_mpi_set_ui(r, 1);
     173           0 :         while (n) { /* square and multiply algorithm for fast exponentiation */
     174           0 :                 n--;
     175           0 :                 gcry_mpi_mulm(r, r, r, phi);
     176           0 :                 if (m & ((uint64_t)1 << n)) {
     177           0 :                         gcry_mpi_add(r, r, r);
     178           0 :                         if (gcry_mpi_cmp(r, phi) >= 0)
     179           0 :                                 gcry_mpi_sub(r, r, phi);
     180             :                 }
     181             :         }
     182             : 
     183           0 :         gcry_mpi_release(phi);
     184           0 :         return r;
     185             : }
     186             : 
     187             : /* Decompose $x \in Z_n$ into $(xp,xq) \in Z_p \times Z_q$ using Chinese Remainder Theorem */
     188           0 : static void CRT_decompose(gcry_mpi_t *xp, gcry_mpi_t *xq, const gcry_mpi_t x, const gcry_mpi_t p, const gcry_mpi_t q) {
     189           0 :         *xp = gcry_mpi_new(0);
     190           0 :         *xq = gcry_mpi_new(0);
     191           0 :         gcry_mpi_mod(*xp, x, p);
     192           0 :         gcry_mpi_mod(*xq, x, q);
     193           0 : }
     194             : 
     195             : /* Compose $(xp,xq) \in Z_p \times Z_q$ into $x \in Z_n$ using Chinese Remainder Theorem */
     196           0 : static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq, const gcry_mpi_t p, const gcry_mpi_t q) {
     197             :         gcry_mpi_t a, u;
     198             : 
     199           0 :         a = gcry_mpi_new(0);
     200           0 :         u = gcry_mpi_new(0);
     201           0 :         *x = gcry_mpi_new(0);
     202           0 :         gcry_mpi_subm(a, xq, xp, q);
     203           0 :         gcry_mpi_invm(u, p, q);
     204           0 :         gcry_mpi_mulm(a, a, u, q); /* a = (xq - xp) / p  (mod q) */
     205           0 :         gcry_mpi_mul(*x, p, a);
     206           0 :         gcry_mpi_add(*x, *x, xp); /* x = p * ((xq - xp) / p mod q) + xp */
     207           0 :         gcry_mpi_release(a);
     208           0 :         gcry_mpi_release(u);
     209           0 : }
     210             : 
     211           0 : static void initialize_libgcrypt(void) {
     212             :         const char *p;
     213           0 :         if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
     214           0 :                 return;
     215             : 
     216           0 :         p = gcry_check_version("1.4.5");
     217           0 :         assert(p);
     218             : 
     219             :         /* Turn off "secmem". Clients which whish to make use of this
     220             :          * feature should initialize the library manually */
     221           0 :         gcry_control(GCRYCTL_DISABLE_SECMEM);
     222           0 :         gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
     223             : }
     224             : 
     225             : /******************************************************************************/
     226             : 
     227           0 : size_t FSPRG_mskinbytes(unsigned _secpar) {
     228           0 :         VALIDATE_SECPAR(_secpar);
     229           0 :         return 2 + 2 * (_secpar / 2) / 8; /* to store header,p,q */
     230             : }
     231             : 
     232           0 : size_t FSPRG_mpkinbytes(unsigned _secpar) {
     233           0 :         VALIDATE_SECPAR(_secpar);
     234           0 :         return 2 + _secpar / 8; /* to store header,n */
     235             : }
     236             : 
     237           0 : size_t FSPRG_stateinbytes(unsigned _secpar) {
     238           0 :         VALIDATE_SECPAR(_secpar);
     239           0 :         return 2 + 2 * _secpar / 8 + 8; /* to store header,n,x,epoch */
     240             : }
     241             : 
     242           0 : static void store_secpar(void *buf, uint16_t secpar) {
     243           0 :         secpar = secpar / 16 - 1;
     244           0 :         ((uint8_t*) buf)[0] = (secpar >> 8) & 0xff;
     245           0 :         ((uint8_t*) buf)[1] = (secpar >> 0) & 0xff;
     246           0 : }
     247             : 
     248           0 : static uint16_t read_secpar(const void *buf) {
     249             :         uint16_t secpar;
     250           0 :         secpar =
     251           0 :                 (uint16_t)(((uint8_t*) buf)[0]) << 8 |
     252           0 :                 (uint16_t)(((uint8_t*) buf)[1]) << 0;
     253           0 :         return 16 * (secpar + 1);
     254             : }
     255             : 
     256           0 : void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned _secpar) {
     257             :         uint8_t iseed[FSPRG_RECOMMENDED_SEEDLEN];
     258             :         gcry_mpi_t n, p, q;
     259             :         uint16_t secpar;
     260             : 
     261           0 :         VALIDATE_SECPAR(_secpar);
     262           0 :         secpar = _secpar;
     263             : 
     264           0 :         initialize_libgcrypt();
     265             : 
     266           0 :         if (!seed) {
     267           0 :                 gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM);
     268           0 :                 seed = iseed;
     269           0 :                 seedlen = FSPRG_RECOMMENDED_SEEDLEN;
     270             :         }
     271             : 
     272           0 :         p = genprime3mod4(secpar / 2, seed, seedlen, RND_GEN_P);
     273           0 :         q = genprime3mod4(secpar / 2, seed, seedlen, RND_GEN_Q);
     274             : 
     275           0 :         if (msk) {
     276           0 :                 store_secpar(msk + 0, secpar);
     277           0 :                 mpi_export(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8, p);
     278           0 :                 mpi_export(msk + 2 + 1 * (secpar / 2) / 8, (secpar / 2) / 8, q);
     279             :         }
     280             : 
     281           0 :         if (mpk) {
     282           0 :                 n = gcry_mpi_new(0);
     283           0 :                 gcry_mpi_mul(n, p, q);
     284           0 :                 assert(gcry_mpi_get_nbits(n) == secpar);
     285             : 
     286           0 :                 store_secpar(mpk + 0, secpar);
     287           0 :                 mpi_export(mpk + 2, secpar / 8, n);
     288             : 
     289           0 :                 gcry_mpi_release(n);
     290             :         }
     291             : 
     292           0 :         gcry_mpi_release(p);
     293           0 :         gcry_mpi_release(q);
     294           0 : }
     295             : 
     296           0 : void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen) {
     297             :         gcry_mpi_t n, x;
     298             :         uint16_t secpar;
     299             : 
     300           0 :         initialize_libgcrypt();
     301             : 
     302           0 :         secpar = read_secpar(mpk + 0);
     303           0 :         n = mpi_import(mpk + 2, secpar / 8);
     304           0 :         x = gensquare(n, seed, seedlen, RND_GEN_X, secpar);
     305             : 
     306           0 :         memcpy(state, mpk, 2 + secpar / 8);
     307           0 :         mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x);
     308           0 :         memzero(state + 2 + 2 * secpar / 8, 8);
     309             : 
     310           0 :         gcry_mpi_release(n);
     311           0 :         gcry_mpi_release(x);
     312           0 : }
     313             : 
     314           0 : void FSPRG_Evolve(void *state) {
     315             :         gcry_mpi_t n, x;
     316             :         uint16_t secpar;
     317             :         uint64_t epoch;
     318             : 
     319           0 :         initialize_libgcrypt();
     320             : 
     321           0 :         secpar = read_secpar(state + 0);
     322           0 :         n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8);
     323           0 :         x = mpi_import(state + 2 + 1 * secpar / 8, secpar / 8);
     324           0 :         epoch = uint64_import(state + 2 + 2 * secpar / 8, 8);
     325             : 
     326           0 :         gcry_mpi_mulm(x, x, x, n);
     327           0 :         epoch++;
     328             : 
     329           0 :         mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x);
     330           0 :         uint64_export(state + 2 + 2 * secpar / 8, 8, epoch);
     331             : 
     332           0 :         gcry_mpi_release(n);
     333           0 :         gcry_mpi_release(x);
     334           0 : }
     335             : 
     336           0 : uint64_t FSPRG_GetEpoch(const void *state) {
     337             :         uint16_t secpar;
     338           0 :         secpar = read_secpar(state + 0);
     339           0 :         return uint64_import(state + 2 + 2 * secpar / 8, 8);
     340             : }
     341             : 
     342           0 : void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen) {
     343             :         gcry_mpi_t p, q, n, x, xp, xq, kp, kq, xm;
     344             :         uint16_t secpar;
     345             : 
     346           0 :         initialize_libgcrypt();
     347             : 
     348           0 :         secpar = read_secpar(msk + 0);
     349           0 :         p  = mpi_import(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8);
     350           0 :         q  = mpi_import(msk + 2 + 1 * (secpar / 2) / 8, (secpar / 2) / 8);
     351             : 
     352           0 :         n = gcry_mpi_new(0);
     353           0 :         gcry_mpi_mul(n, p, q);
     354             : 
     355           0 :         x = gensquare(n, seed, seedlen, RND_GEN_X, secpar);
     356           0 :         CRT_decompose(&xp, &xq, x, p, q); /* split (mod n) into (mod p) and (mod q) using CRT */
     357             : 
     358           0 :         kp = twopowmodphi(epoch, p); /* compute 2^epoch (mod phi(p)) */
     359           0 :         kq = twopowmodphi(epoch, q); /* compute 2^epoch (mod phi(q)) */
     360             : 
     361           0 :         gcry_mpi_powm(xp, xp, kp, p); /* compute x^(2^epoch) (mod p) */
     362           0 :         gcry_mpi_powm(xq, xq, kq, q); /* compute x^(2^epoch) (mod q) */
     363             : 
     364           0 :         CRT_compose(&xm, xp, xq, p, q); /* combine (mod p) and (mod q) to (mod n) using CRT */
     365             : 
     366           0 :         store_secpar(state + 0, secpar);
     367           0 :         mpi_export(state + 2 + 0 * secpar / 8, secpar / 8, n);
     368           0 :         mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, xm);
     369           0 :         uint64_export(state + 2 + 2 * secpar / 8, 8, epoch);
     370             : 
     371           0 :         gcry_mpi_release(p);
     372           0 :         gcry_mpi_release(q);
     373           0 :         gcry_mpi_release(n);
     374           0 :         gcry_mpi_release(x);
     375           0 :         gcry_mpi_release(xp);
     376           0 :         gcry_mpi_release(xq);
     377           0 :         gcry_mpi_release(kp);
     378           0 :         gcry_mpi_release(kq);
     379           0 :         gcry_mpi_release(xm);
     380           0 : }
     381             : 
     382           0 : void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) {
     383             :         uint16_t secpar;
     384             : 
     385           0 :         initialize_libgcrypt();
     386             : 
     387           0 :         secpar = read_secpar(state + 0);
     388           0 :         det_randomize(key, keylen, state + 2, 2 * secpar / 8 + 8, idx);
     389           0 : }

Generated by: LCOV version 1.11