crypto_libtomcrypt.c
Go to the documentation of this file.
00001 /*
00002  * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
00003  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 #include <tomcrypt.h>
00017 
00018 #include "common.h"
00019 #include "crypto.h"
00020 
00021 #ifndef mp_init_multi
00022 #define mp_init_multi                ltc_init_multi
00023 #define mp_clear_multi               ltc_deinit_multi
00024 #define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
00025 #define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
00026 #define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
00027 #define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
00028 #endif
00029 
00030 
00031 int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
00032 {
00033         hash_state md;
00034         size_t i;
00035 
00036         md4_init(&md);
00037         for (i = 0; i < num_elem; i++)
00038                 md4_process(&md, addr[i], len[i]);
00039         md4_done(&md, mac);
00040         return 0;
00041 }
00042 
00043 
00044 void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
00045 {
00046         u8 pkey[8], next, tmp;
00047         int i;
00048         symmetric_key skey;
00049 
00050         /* Add parity bits to the key */
00051         next = 0;
00052         for (i = 0; i < 7; i++) {
00053                 tmp = key[i];
00054                 pkey[i] = (tmp >> i) | next | 1;
00055                 next = tmp << (7 - i);
00056         }
00057         pkey[i] = next | 1;
00058 
00059         des_setup(pkey, 8, 0, &skey);
00060         des_ecb_encrypt(clear, cypher, &skey);
00061         des_done(&skey);
00062 }
00063 
00064 
00065 int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
00066 {
00067         hash_state md;
00068         size_t i;
00069 
00070         md5_init(&md);
00071         for (i = 0; i < num_elem; i++)
00072                 md5_process(&md, addr[i], len[i]);
00073         md5_done(&md, mac);
00074         return 0;
00075 }
00076 
00077 
00078 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
00079 {
00080         hash_state md;
00081         size_t i;
00082 
00083         sha1_init(&md);
00084         for (i = 0; i < num_elem; i++)
00085                 sha1_process(&md, addr[i], len[i]);
00086         sha1_done(&md, mac);
00087         return 0;
00088 }
00089 
00090 
00091 void * aes_encrypt_init(const u8 *key, size_t len)
00092 {
00093         symmetric_key *skey;
00094         skey = os_malloc(sizeof(*skey));
00095         if (skey == NULL)
00096                 return NULL;
00097         if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
00098                 os_free(skey);
00099                 return NULL;
00100         }
00101         return skey;
00102 }
00103 
00104 
00105 void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
00106 {
00107         symmetric_key *skey = ctx;
00108         aes_ecb_encrypt(plain, crypt, skey);
00109 }
00110 
00111 
00112 void aes_encrypt_deinit(void *ctx)
00113 {
00114         symmetric_key *skey = ctx;
00115         aes_done(skey);
00116         os_free(skey);
00117 }
00118 
00119 
00120 void * aes_decrypt_init(const u8 *key, size_t len)
00121 {
00122         symmetric_key *skey;
00123         skey = os_malloc(sizeof(*skey));
00124         if (skey == NULL)
00125                 return NULL;
00126         if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
00127                 os_free(skey);
00128                 return NULL;
00129         }
00130         return skey;
00131 }
00132 
00133 
00134 void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
00135 {
00136         symmetric_key *skey = ctx;
00137         aes_ecb_encrypt(plain, (u8 *) crypt, skey);
00138 }
00139 
00140 
00141 void aes_decrypt_deinit(void *ctx)
00142 {
00143         symmetric_key *skey = ctx;
00144         aes_done(skey);
00145         os_free(skey);
00146 }
00147 
00148 
00149 struct crypto_hash {
00150         enum crypto_hash_alg alg;
00151         int error;
00152         union {
00153                 hash_state md;
00154                 hmac_state hmac;
00155         } u;
00156 };
00157 
00158 
00159 struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
00160                                       size_t key_len)
00161 {
00162         struct crypto_hash *ctx;
00163 
00164         ctx = os_zalloc(sizeof(*ctx));
00165         if (ctx == NULL)
00166                 return NULL;
00167 
00168         ctx->alg = alg;
00169 
00170         switch (alg) {
00171         case CRYPTO_HASH_ALG_MD5:
00172                 if (md5_init(&ctx->u.md) != CRYPT_OK)
00173                         goto fail;
00174                 break;
00175         case CRYPTO_HASH_ALG_SHA1:
00176                 if (sha1_init(&ctx->u.md) != CRYPT_OK)
00177                         goto fail;
00178                 break;
00179         case CRYPTO_HASH_ALG_HMAC_MD5:
00180                 if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
00181                     CRYPT_OK)
00182                         goto fail;
00183                 break;
00184         case CRYPTO_HASH_ALG_HMAC_SHA1:
00185                 if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
00186                     CRYPT_OK)
00187                         goto fail;
00188                 break;
00189         default:
00190                 goto fail;
00191         }
00192 
00193         return ctx;
00194 
00195 fail:
00196         os_free(ctx);
00197         return NULL;
00198 }
00199 
00200 void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
00201 {
00202         if (ctx == NULL || ctx->error)
00203                 return;
00204 
00205         switch (ctx->alg) {
00206         case CRYPTO_HASH_ALG_MD5:
00207                 ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
00208                 break;
00209         case CRYPTO_HASH_ALG_SHA1:
00210                 ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
00211                 break;
00212         case CRYPTO_HASH_ALG_HMAC_MD5:
00213         case CRYPTO_HASH_ALG_HMAC_SHA1:
00214                 ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
00215                 break;
00216         }
00217 }
00218 
00219 
00220 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
00221 {
00222         int ret = 0;
00223         unsigned long clen;
00224 
00225         if (ctx == NULL)
00226                 return -2;
00227 
00228         if (mac == NULL || len == NULL) {
00229                 os_free(ctx);
00230                 return 0;
00231         }
00232 
00233         if (ctx->error) {
00234                 os_free(ctx);
00235                 return -2;
00236         }
00237 
00238         switch (ctx->alg) {
00239         case CRYPTO_HASH_ALG_MD5:
00240                 if (*len < 16) {
00241                         *len = 16;
00242                         os_free(ctx);
00243                         return -1;
00244                 }
00245                 *len = 16;
00246                 if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
00247                         ret = -2;
00248                 break;
00249         case CRYPTO_HASH_ALG_SHA1:
00250                 if (*len < 20) {
00251                         *len = 20;
00252                         os_free(ctx);
00253                         return -1;
00254                 }
00255                 *len = 20;
00256                 if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
00257                         ret = -2;
00258                 break;
00259         case CRYPTO_HASH_ALG_HMAC_SHA1:
00260                 if (*len < 20) {
00261                         *len = 20;
00262                         os_free(ctx);
00263                         return -1;
00264                 }
00265                 /* continue */
00266         case CRYPTO_HASH_ALG_HMAC_MD5:
00267                 if (*len < 16) {
00268                         *len = 16;
00269                         os_free(ctx);
00270                         return -1;
00271                 }
00272                 clen = *len;
00273                 if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
00274                         os_free(ctx);
00275                         return -1;
00276                 }
00277                 *len = clen;
00278                 break;
00279         default:
00280                 ret = -2;
00281                 break;
00282         }
00283 
00284         os_free(ctx);
00285 
00286         return ret;
00287 }
00288 
00289 
00290 struct crypto_cipher {
00291         int rc4;
00292         union {
00293                 symmetric_CBC cbc;
00294                 struct {
00295                         size_t used_bytes;
00296                         u8 key[16];
00297                         size_t keylen;
00298                 } rc4;
00299         } u;
00300 };
00301 
00302 
00303 struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
00304                                           const u8 *iv, const u8 *key,
00305                                           size_t key_len)
00306 {       
00307         struct crypto_cipher *ctx;
00308         int idx, res, rc4 = 0;
00309 
00310         switch (alg) {
00311         case CRYPTO_CIPHER_ALG_AES:
00312                 idx = find_cipher("aes");
00313                 break;
00314         case CRYPTO_CIPHER_ALG_3DES:
00315                 idx = find_cipher("3des");
00316                 break;
00317         case CRYPTO_CIPHER_ALG_DES:
00318                 idx = find_cipher("des");
00319                 break;
00320         case CRYPTO_CIPHER_ALG_RC2:
00321                 idx = find_cipher("rc2");
00322                 break;
00323         case CRYPTO_CIPHER_ALG_RC4:
00324                 idx = -1;
00325                 rc4 = 1;
00326                 break;
00327         default:
00328                 return NULL;
00329         }
00330 
00331         ctx = os_zalloc(sizeof(*ctx));
00332         if (ctx == NULL)
00333                 return NULL;
00334 
00335         if (rc4) {
00336                 ctx->rc4 = 1;
00337                 if (key_len > sizeof(ctx->u.rc4.key)) {
00338                         os_free(ctx);
00339                         return NULL;
00340                 }
00341                 ctx->u.rc4.keylen = key_len;
00342                 os_memcpy(ctx->u.rc4.key, key, key_len);
00343         } else {
00344                 res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
00345                 if (res != CRYPT_OK) {
00346                         wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
00347                                    "failed: %s", error_to_string(res));
00348                         os_free(ctx);
00349                         return NULL;
00350                 }
00351         }
00352 
00353         return ctx;
00354 }
00355 
00356 int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
00357                           u8 *crypt, size_t len)
00358 {
00359         int res;
00360 
00361         if (ctx->rc4) {
00362                 if (plain != crypt)
00363                         os_memcpy(crypt, plain, len);
00364                 rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
00365                          ctx->u.rc4.used_bytes, crypt, len);
00366                 ctx->u.rc4.used_bytes += len;
00367                 return 0;
00368         }
00369 
00370         res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
00371         if (res != CRYPT_OK) {
00372                 wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
00373                            "failed: %s", error_to_string(res));
00374                 return -1;
00375         }
00376         return 0;
00377 }
00378 
00379 
00380 int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
00381                           u8 *plain, size_t len)
00382 {
00383         int res;
00384 
00385         if (ctx->rc4) {
00386                 if (plain != crypt)
00387                         os_memcpy(plain, crypt, len);
00388                 rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
00389                          ctx->u.rc4.used_bytes, plain, len);
00390                 ctx->u.rc4.used_bytes += len;
00391                 return 0;
00392         }
00393 
00394         res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
00395         if (res != CRYPT_OK) {
00396                 wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
00397                            "failed: %s", error_to_string(res));
00398                 return -1;
00399         }
00400 
00401         return 0;
00402 }
00403 
00404 
00405 void crypto_cipher_deinit(struct crypto_cipher *ctx)
00406 {
00407         if (!ctx->rc4)
00408                 cbc_done(&ctx->u.cbc);
00409         os_free(ctx);
00410 }
00411 
00412 
00413 struct crypto_public_key {
00414         rsa_key rsa;
00415 };
00416 
00417 struct crypto_private_key {
00418         rsa_key rsa;
00419 };
00420 
00421 
00422 struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
00423 {
00424         int res;
00425         struct crypto_public_key *pk;
00426 
00427         pk = os_zalloc(sizeof(*pk));
00428         if (pk == NULL)
00429                 return NULL;
00430 
00431         res = rsa_import(key, len, &pk->rsa);
00432         if (res != CRYPT_OK) {
00433                 wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
00434                            "public key (res=%d '%s')",
00435                            res, error_to_string(res));
00436                 os_free(pk);
00437                 return NULL;
00438         }
00439 
00440         if (pk->rsa.type != PK_PUBLIC) {
00441                 wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
00442                            "correct type");
00443                 rsa_free(&pk->rsa);
00444                 os_free(pk);
00445                 return NULL;
00446         }
00447 
00448         return pk;
00449 }
00450 
00451 
00452 struct crypto_private_key * crypto_private_key_import(const u8 *key,
00453                                                       size_t len,
00454                                                       const char *passwd)
00455 {
00456         int res;
00457         struct crypto_private_key *pk;
00458 
00459         pk = os_zalloc(sizeof(*pk));
00460         if (pk == NULL)
00461                 return NULL;
00462 
00463         res = rsa_import(key, len, &pk->rsa);
00464         if (res != CRYPT_OK) {
00465                 wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
00466                            "private key (res=%d '%s')",
00467                            res, error_to_string(res));
00468                 os_free(pk);
00469                 return NULL;
00470         }
00471 
00472         if (pk->rsa.type != PK_PRIVATE) {
00473                 wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
00474                            "correct type");
00475                 rsa_free(&pk->rsa);
00476                 os_free(pk);
00477                 return NULL;
00478         }
00479 
00480         return pk;
00481 }
00482 
00483 
00484 struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
00485                                                        size_t len)
00486 {
00487         /* No X.509 support in LibTomCrypt */
00488         return NULL;
00489 }
00490 
00491 
00492 static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
00493                                            const u8 *in, size_t inlen,
00494                                            u8 *out, size_t *outlen)
00495 {
00496         size_t ps_len;
00497         u8 *pos;
00498 
00499         /*
00500          * PKCS #1 v1.5, 8.1:
00501          *
00502          * EB = 00 || BT || PS || 00 || D
00503          * BT = 00 or 01 for private-key operation; 02 for public-key operation
00504          * PS = k-3-||D||; at least eight octets
00505          * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
00506          * k = length of modulus in octets (modlen)
00507          */
00508 
00509         if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
00510                 wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
00511                            "lengths (modlen=%lu outlen=%lu inlen=%lu)",
00512                            __func__, (unsigned long) modlen,
00513                            (unsigned long) *outlen,
00514                            (unsigned long) inlen);
00515                 return -1;
00516         }
00517 
00518         pos = out;
00519         *pos++ = 0x00;
00520         *pos++ = block_type; /* BT */
00521         ps_len = modlen - inlen - 3;
00522         switch (block_type) {
00523         case 0:
00524                 os_memset(pos, 0x00, ps_len);
00525                 pos += ps_len;
00526                 break;
00527         case 1:
00528                 os_memset(pos, 0xff, ps_len);
00529                 pos += ps_len;
00530                 break;
00531         case 2:
00532                 if (os_get_random(pos, ps_len) < 0) {
00533                         wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
00534                                    "random data for PS", __func__);
00535                         return -1;
00536                 }
00537                 while (ps_len--) {
00538                         if (*pos == 0x00)
00539                                 *pos = 0x01;
00540                         pos++;
00541                 }
00542                 break;
00543         default:
00544                 wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
00545                            "%d", __func__, block_type);
00546                 return -1;
00547         }
00548         *pos++ = 0x00;
00549         os_memcpy(pos, in, inlen); /* D */
00550 
00551         return 0;
00552 }
00553 
00554 
00555 static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
00556                                     const u8 *in, size_t inlen,
00557                                     u8 *out, size_t *outlen)
00558 {
00559         unsigned long len, modlen;
00560         int res;
00561 
00562         modlen = mp_unsigned_bin_size(key->N);
00563 
00564         if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
00565                                             out, outlen) < 0)
00566                 return -1;
00567 
00568         len = *outlen;
00569         res = rsa_exptmod(out, modlen, out, &len, key_type, key);
00570         if (res != CRYPT_OK) {
00571                 wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
00572                            error_to_string(res));
00573                 return -1;
00574         }
00575         *outlen = len;
00576 
00577         return 0;
00578 }
00579 
00580 
00581 int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
00582                                         const u8 *in, size_t inlen,
00583                                         u8 *out, size_t *outlen)
00584 {
00585         return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
00586                                         out, outlen);
00587 }
00588 
00589 
00590 int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
00591                                   const u8 *in, size_t inlen,
00592                                   u8 *out, size_t *outlen)
00593 {
00594         return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
00595                                         out, outlen);
00596 }
00597 
00598 
00599 void crypto_public_key_free(struct crypto_public_key *key)
00600 {
00601         if (key) {
00602                 rsa_free(&key->rsa);
00603                 os_free(key);
00604         }
00605 }
00606 
00607 
00608 void crypto_private_key_free(struct crypto_private_key *key)
00609 {
00610         if (key) {
00611                 rsa_free(&key->rsa);
00612                 os_free(key);
00613         }
00614 }
00615 
00616 
00617 int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
00618                                     const u8 *crypt, size_t crypt_len,
00619                                     u8 *plain, size_t *plain_len)
00620 {
00621         int res;
00622         unsigned long len;
00623         u8 *pos;
00624 
00625         len = *plain_len;
00626         res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
00627                           &key->rsa);
00628         if (res != CRYPT_OK) {
00629                 wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
00630                            error_to_string(res));
00631                 return -1;
00632         }
00633 
00634         /*
00635          * PKCS #1 v1.5, 8.1:
00636          *
00637          * EB = 00 || BT || PS || 00 || D
00638          * BT = 01
00639          * PS = k-3-||D|| times FF
00640          * k = length of modulus in octets
00641          */
00642 
00643         if (len < 3 + 8 + 16 /* min hash len */ ||
00644             plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
00645                 wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
00646                            "structure");
00647                 return -1;
00648         }
00649 
00650         pos = plain + 3;
00651         while (pos < plain + len && *pos == 0xff)
00652                 pos++;
00653         if (pos - plain - 2 < 8) {
00654                 /* PKCS #1 v1.5, 8.1: At least eight octets long PS */
00655                 wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
00656                            "padding");
00657                 return -1;
00658         }
00659 
00660         if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
00661                 wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
00662                            "structure (2)");
00663                 return -1;
00664         }
00665         pos++;
00666         len -= pos - plain;
00667 
00668         /* Strip PKCS #1 header */
00669         os_memmove(plain, pos, len);
00670         *plain_len = len;
00671 
00672         return 0;
00673 }
00674 
00675 
00676 int crypto_global_init(void)
00677 {
00678         ltc_mp = tfm_desc;
00679         /* TODO: only register algorithms that are really needed */
00680         if (register_hash(&md4_desc) < 0 ||
00681             register_hash(&md5_desc) < 0 ||
00682             register_hash(&sha1_desc) < 0 ||
00683             register_cipher(&aes_desc) < 0 ||
00684             register_cipher(&des_desc) < 0 ||
00685             register_cipher(&des3_desc) < 0) {
00686                 wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
00687                            "hash/cipher functions");
00688                 return -1;
00689         }
00690 
00691         return 0;
00692 }
00693 
00694 
00695 void crypto_global_deinit(void)
00696 {
00697 }
00698 
00699 
00700 #ifdef CONFIG_MODEXP
00701 
00702 int crypto_mod_exp(const u8 *base, size_t base_len,
00703                    const u8 *power, size_t power_len,
00704                    const u8 *modulus, size_t modulus_len,
00705                    u8 *result, size_t *result_len)
00706 {
00707         void *b, *p, *m, *r;
00708 
00709         if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
00710                 return -1;
00711 
00712         if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
00713             mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
00714             mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
00715                 goto fail;
00716 
00717         if (mp_exptmod(b, p, m, r) != CRYPT_OK)
00718                 goto fail;
00719 
00720         *result_len = mp_unsigned_bin_size(r);
00721         if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
00722                 goto fail;
00723 
00724         mp_clear_multi(b, p, m, r, NULL);
00725         return 0;
00726 
00727 fail:
00728         mp_clear_multi(b, p, m, r, NULL);
00729         return -1;
00730 }
00731 
00732 #endif /* CONFIG_MODEXP */


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:33