1e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include <openssl/opensslconf.h> 2e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 3e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#ifdef OPENSSL_NO_JPAKE 4e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 5e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include <stdio.h> 6e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 7e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguint main(int argc, char *argv[]) 8e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu{ 9e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("No J-PAKE support\n"); 10e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return(0); 11e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu} 12e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 13e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#else 14e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 15e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include <openssl/jpake.h> 16e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include <openssl/err.h> 17e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 18e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugustatic void showbn(const char *name, const BIGNUM *bn) 19e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 20e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu fputs(name, stdout); 21e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu fputs(" = ", stdout); 22e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_print_fp(stdout, bn); 23e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu putc('\n', stdout); 24e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 25e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 26e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugustatic int run_jpake(JPAKE_CTX *alice, JPAKE_CTX *bob) 27e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 28e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1 alice_s1; 29e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1 bob_s1; 30e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2 alice_s2; 31e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2 bob_s2; 32e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3A alice_s3a; 33e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3B bob_s3b; 34e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 35e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Alice -> Bob: step 1 */ 36e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu puts("A->B s1"); 37e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1_init(&alice_s1); 38e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1_generate(&alice_s1, alice); 39e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(!JPAKE_STEP1_process(bob, &alice_s1)) 40e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 41e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("Bob fails to process Alice's step 1\n"); 42e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_print_errors_fp(stdout); 43e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 1; 44e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 45e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1_release(&alice_s1); 46e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 47e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Bob -> Alice: step 1 */ 48e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu puts("B->A s1"); 49e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1_init(&bob_s1); 50e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1_generate(&bob_s1, bob); 51e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(!JPAKE_STEP1_process(alice, &bob_s1)) 52e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 53e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("Alice fails to process Bob's step 1\n"); 54e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_print_errors_fp(stdout); 55e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 2; 56e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 57e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP1_release(&bob_s1); 58e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 59e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Alice -> Bob: step 2 */ 60e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu puts("A->B s2"); 61e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2_init(&alice_s2); 62e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2_generate(&alice_s2, alice); 63e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(!JPAKE_STEP2_process(bob, &alice_s2)) 64e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 65e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("Bob fails to process Alice's step 2\n"); 66e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_print_errors_fp(stdout); 67e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 3; 68e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 69e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2_release(&alice_s2); 70e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 71e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Bob -> Alice: step 2 */ 72e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu puts("B->A s2"); 73e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2_init(&bob_s2); 74e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2_generate(&bob_s2, bob); 75e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(!JPAKE_STEP2_process(alice, &bob_s2)) 76e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 77e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("Alice fails to process Bob's step 2\n"); 78e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_print_errors_fp(stdout); 79e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 4; 80e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 81e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP2_release(&bob_s2); 82e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 83e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu showbn("Alice's key", JPAKE_get_shared_key(alice)); 84e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu showbn("Bob's key ", JPAKE_get_shared_key(bob)); 85e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 86e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Alice -> Bob: step 3a */ 87e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu puts("A->B s3a"); 88e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3A_init(&alice_s3a); 89e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3A_generate(&alice_s3a, alice); 90e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(!JPAKE_STEP3A_process(bob, &alice_s3a)) 91e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 92e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("Bob fails to process Alice's step 3a\n"); 93e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_print_errors_fp(stdout); 94e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 5; 95e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 96e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3A_release(&alice_s3a); 97e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 98e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Bob -> Alice: step 3b */ 99e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu puts("B->A s3b"); 100e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3B_init(&bob_s3b); 101e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3B_generate(&bob_s3b, bob); 102e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(!JPAKE_STEP3B_process(alice, &bob_s3b)) 103e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 104e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu printf("Alice fails to process Bob's step 3b\n"); 105e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_print_errors_fp(stdout); 106e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 6; 107e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 108e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_STEP3B_release(&bob_s3b); 109e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 110e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 0; 111e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 112e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 113e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguint main(int argc, char **argv) 114e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 115e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_CTX *alice; 116e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_CTX *bob; 117e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BIGNUM *p = NULL; 118e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BIGNUM *g = NULL; 119e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BIGNUM *q = NULL; 120e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BIGNUM *secret = BN_new(); 121e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BIO *bio_err; 122e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 123e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); 124e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 125e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu CRYPTO_malloc_debug_init(); 126e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL); 127e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); 128e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 129e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_load_crypto_strings(); 130e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 131e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* 132e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_hex2bn(&p, "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7"); 133e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_hex2bn(&g, "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a"); 134e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_hex2bn(&q, "9760508f15230bccb292b982a2eb840bf0581cf5"); 135e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu */ 136e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* 137e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu p = BN_new(); 138e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_generate_prime(p, 1024, 1, NULL, NULL, NULL, NULL); 139e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu */ 140e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Use a safe prime for p (that we found earlier) */ 141e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_hex2bn(&p, "F9E5B365665EA7A05A9C534502780FEE6F1AB5BD4F49947FD036DBD7E905269AF46EF28B0FC07487EE4F5D20FB3C0AF8E700F3A2FA3414970CBED44FEDFF80CE78D800F184BB82435D137AADA2C6C16523247930A63B85661D1FC817A51ACD96168E95898A1F83A79FFB529368AA7833ABD1B0C3AEDDB14D2E1A2F71D99F763F"); 142e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu showbn("p", p); 143e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu g = BN_new(); 144e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_set_word(g, 2); 145e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu showbn("g", g); 146e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu q = BN_new(); 147e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_rshift1(q, p); 148e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu showbn("q", q); 149e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 150e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_rand(secret, 32, -1, 0); 151e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 152e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* A normal run, expect this to work... */ 153e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu alice = JPAKE_CTX_new("Alice", "Bob", p, g, q, secret); 154e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu bob = JPAKE_CTX_new("Bob", "Alice", p, g, q, secret); 155e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 156e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(run_jpake(alice, bob) != 0) 157e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 158e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu fprintf(stderr, "Plain JPAKE run failed\n"); 159e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 1; 160e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 161e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 162e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_CTX_free(bob); 163e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_CTX_free(alice); 164e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 165e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu /* Now give Alice and Bob different secrets */ 166e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu alice = JPAKE_CTX_new("Alice", "Bob", p, g, q, secret); 167e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_add_word(secret, 1); 168e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu bob = JPAKE_CTX_new("Bob", "Alice", p, g, q, secret); 169e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 170e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu if(run_jpake(alice, bob) != 5) 171e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu { 172e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu fprintf(stderr, "Mismatched secret JPAKE run failed\n"); 173e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 1; 174e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 175e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 176e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_CTX_free(bob); 177e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu JPAKE_CTX_free(alice); 178e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 179e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_free(secret); 180e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_free(q); 181e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_free(g); 182e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu BN_free(p); 183e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 184e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu CRYPTO_cleanup_all_ex_data(); 185221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom ERR_remove_thread_state(NULL); 186e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu ERR_free_strings(); 187e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu CRYPTO_mem_leaks(bio_err); 188e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 189e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu return 0; 190e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu } 191e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu 192e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#endif 193