struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point) { struct secret *ss = tal(ctx, struct secret); if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, notsosecret.data, NULL, NULL) != 1) return tal_free(ss); return ss; }
static void bench_ecdh(void* arg) { int i; unsigned char res[32]; bench_ecdh_t *data = (bench_ecdh_t*)arg; for (i = 0; i < 20000; i++) { CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); } }
SECP256K1_API jobjectArray JNICALL Java_org_commercium_NativeSecp256k1_secp256k1_1ecdh (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* pubdata = (const unsigned char*) (secdata + 32); jobjectArray retArray; jbyteArray outArray, intsByteArray; unsigned char intsarray[1]; secp256k1_pubkey pubkey; unsigned char nonce_res[32]; size_t outputLen = 32; int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); if (ret) { ret = secp256k1_ecdh( ctx, nonce_res, &pubkey, secdata ); } intsarray[0] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); outArray = (*env)->NewByteArray(env, outputLen); (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); (*env)->SetObjectArrayElement(env, retArray, 0, outArray); intsByteArray = (*env)->NewByteArray(env, 1); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; }
/* * Decrypt onion, return true if onion->hop[0] is valid. * * Returns enckey and pad_iv for use in unwrap. */ static bool decrypt_onion(const struct seckey *myseckey, struct onion *onion, struct enckey *enckey, struct iv *pad_iv) { secp256k1_context *ctx; unsigned char secret[32]; struct hmackey hmackey; struct iv iv; secp256k1_pubkey pubkey; ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); if (!pubkey_parse(ctx, &pubkey, &myhop(onion)->pubkey)) goto fail; /* Extract shared secret. */ if (!secp256k1_ecdh(ctx, secret, &pubkey, myseckey->u.u8)) goto fail; hmackey = hmackey_from_secret(secret); *enckey = enckey_from_secret(secret); ivs_from_secret(secret, &iv, pad_iv); /* Check HMAC. */ #if 0 printf("Checking HMAC using key%02x%02x%02x%02x%02x%02x%02x%02x (offset %u len %zu) for %02x%02x%02x%02x%02x%02x%02x%02x...%02x%02x%02x\n", hmackey.k[0], hmackey.k[1], hmackey.k[2], hmackey.k[3], hmackey.k[4], hmackey.k[5], hmackey.k[6], hmackey.k[7], SHA256_DIGEST_LENGTH, sizeof(*onion) - SHA256_DIGEST_LENGTH, ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[0], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[1], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[2], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[3], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[4], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[5], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[6], ((unsigned char *)onion + SHA256_DIGEST_LENGTH)[7], ((unsigned char *)(onion + 1))[-3], ((unsigned char *)(onion + 1))[-2], ((unsigned char *)(onion + 1))[-1]); dump_contents((unsigned char *)onion + SHA256_DIGEST_LENGTH, sizeof(*onion) - SHA256_DIGEST_LENGTH); #endif if (!check_hmac(onion, &hmackey)) goto fail; /* Decrypt everything up to pubkey. */ /* FIXME: Assumes we can decrypt in place! */ if (!aes_decrypt(onion, onion, sizeof(struct hop) * (MAX_HOPS-1) + sizeof(myhop(onion)->msg), enckey, &iv)) goto fail; secp256k1_context_destroy(ctx); return true; fail: secp256k1_context_destroy(ctx); return false; }
static bool create_onion(const secp256k1_pubkey pubkey[], char *const msg[], size_t num, struct onion *onion) { int i; struct seckey seckeys[MAX_HOPS]; struct onion_pubkey pubkeys[MAX_HOPS]; struct enckey enckeys[MAX_HOPS]; struct hmackey hmackeys[MAX_HOPS]; struct iv ivs[MAX_HOPS]; struct iv pad_ivs[MAX_HOPS]; HMAC_CTX padding_hmac[MAX_HOPS]; struct hop padding[MAX_HOPS]; size_t junk_hops; secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); bool ok = false; if (num > MAX_HOPS) goto fail; /* FIXME: I think it would be safe to reuse a single disposable key * here? */ /* First generate all the keys. */ for (i = 0; i < num; i++) { unsigned char secret[32]; gen_keys(ctx, &seckeys[i], &pubkeys[i]); /* Make shared secret. */ if (!secp256k1_ecdh(ctx, secret, &pubkey[i], seckeys[i].u.u8)) goto fail; hmackeys[i] = hmackey_from_secret(memcheck(secret, 32)); enckeys[i] = enckey_from_secret(secret); ivs_from_secret(secret, &ivs[i], &pad_ivs[i]); } /* * Building the onion is a little tricky. * * First, there is the padding. That's generated by previous nodes, * and "decrypted" by the others. So we have to generate that * forwards. */ for (i = 0; i < num; i++) { if (i > 0) { /* Previous node decrypts padding before passing on. */ aes_decrypt(padding, padding, sizeof(struct hop)*(i-1), &enckeys[i-1], &ivs[i-1]); memmove(padding + 1, padding, sizeof(struct hop)*(i-1)); } /* And generates more padding for next node. */ add_padding(&padding[0], &enckeys[i-1], &pad_ivs[i-1]); HMAC_CTX_init(&padding_hmac[i]); HMAC_Init_ex(&padding_hmac[i], hmackeys[i].k.u.u8, sizeof(hmackeys[i].k), EVP_sha256(), NULL); HMAC_Update(&padding_hmac[i], memcheck((unsigned char *)padding, i * sizeof(struct hop)), i * sizeof(struct hop)); } /* * Now the normal onion is generated backwards. */ /* Unused hops filled with random, so even recipient can't tell * how many were used. */ junk_hops = MAX_HOPS - num; random_bytes(onion->hop, junk_hops * sizeof(struct hop)); for (i = num - 1; i >= 0; i--) { size_t other_hops, len; struct hop *myhop; other_hops = num - i - 1 + junk_hops; /* Our entry is at tail of onion. */ myhop = onion->hop + other_hops; /* Now populate our hop. */ myhop->pubkey = pubkeys[i]; /* Set message. */ assert(strlen(msg[i]) < MESSAGE_SIZE); memset(myhop->msg, 0, MESSAGE_SIZE); strcpy((char *)myhop->msg, msg[i]); /* Encrypt whole thing, including our message, but we * aware it will be offset by the prepended padding. */ if (!aes_encrypt_offset(i * sizeof(struct hop), onion, onion, other_hops * sizeof(struct hop) + sizeof(myhop->msg), &enckeys[i], &ivs[i])) goto fail; /* HMAC covers entire thing except hmac itself. */ len = (other_hops + 1)*sizeof(struct hop) - sizeof(myhop->hmac); HMAC_Update(&padding_hmac[i], memcheck((unsigned char *)onion, len), len); HMAC_Final(&padding_hmac[i], myhop->hmac.u.u8, NULL); } ok = true; fail: secp256k1_context_destroy(ctx); return ok; }