1545N/A/*
3909N/A * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
1545N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1545N/A *
1545N/A * This code is free software; you can redistribute it and/or modify it
1545N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
1545N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
1545N/A *
1545N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1545N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1545N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1545N/A * version 2 for more details (a copy is included in the LICENSE file that
1545N/A * accompanied this code).
1545N/A *
1545N/A * You should have received a copy of the GNU General Public License version
1545N/A * 2 along with this work; if not, write to the Free Software Foundation,
1545N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1545N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
1545N/A */
1545N/A
1545N/A#include <jni.h>
1674N/A#include "impl/ecc_impl.h"
1545N/A
1545N/A#define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
1545N/A#define INVALID_ALGORITHM_PARAMETER_EXCEPTION \
1545N/A "java/security/InvalidAlgorithmParameterException"
1545N/A#define INVALID_PARAMETER_EXCEPTION \
1545N/A "java/security/InvalidParameterException"
1545N/A#define KEY_EXCEPTION "java/security/KeyException"
1545N/A
1545N/Aextern "C" {
1545N/A
1545N/A/*
1545N/A * Throws an arbitrary Java exception.
1545N/A */
3488N/Avoid ThrowException(JNIEnv *env, const char *exceptionName)
1545N/A{
1545N/A jclass exceptionClazz = env->FindClass(exceptionName);
1545N/A env->ThrowNew(exceptionClazz, NULL);
1545N/A}
1545N/A
1545N/A/*
1545N/A * Deep free of the ECParams struct
1545N/A */
1545N/Avoid FreeECParams(ECParams *ecparams, jboolean freeStruct)
1545N/A{
1545N/A // Use B_FALSE to free the SECItem->data element, but not the SECItem itself
1545N/A // Use B_TRUE to free both
1545N/A
1545N/A SECITEM_FreeItem(&ecparams->fieldID.u.prime, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->curve.a, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->curve.b, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->curve.seed, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->base, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->order, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->DEREncoding, B_FALSE);
1545N/A SECITEM_FreeItem(&ecparams->curveOID, B_FALSE);
1545N/A if (freeStruct)
1545N/A free(ecparams);
1545N/A}
1545N/A
1545N/A/*
1545N/A * Class: sun_security_ec_ECKeyPairGenerator
1545N/A * Method: generateECKeyPair
1545N/A * Signature: (I[B[B)[J
1545N/A */
1545N/AJNIEXPORT jlongArray
1545N/AJNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
1545N/A (JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed)
1545N/A{
1545N/A ECPrivateKey *privKey; /* contains both public and private values */
1545N/A ECParams *ecparams = NULL;
1545N/A SECKEYECParams params_item;
1545N/A jint jSeedLength;
1545N/A jbyte* pSeedBuffer = NULL;
1545N/A jlongArray result = NULL;
1545N/A jlong* resultElements = NULL;
1545N/A
1545N/A // Initialize the ECParams struct
1545N/A params_item.len = env->GetArrayLength(encodedParams);
1545N/A params_item.data =
1545N/A (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
1545N/A
1545N/A // Fill a new ECParams using the supplied OID
1545N/A if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
1545N/A /* bad curve OID */
3488N/A ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A // Copy seed from Java to native buffer
1545N/A jSeedLength = env->GetArrayLength(seed);
1545N/A pSeedBuffer = new jbyte[jSeedLength];
1545N/A env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
1545N/A
1545N/A // Generate the new keypair (using the supplied seed)
1545N/A if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer,
1545N/A jSeedLength, 0) != SECSuccess) {
3488N/A ThrowException(env, KEY_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A jboolean isCopy;
1545N/A result = env->NewLongArray(2);
1545N/A resultElements = env->GetLongArrayElements(result, &isCopy);
1545N/A
1545N/A resultElements[0] = (jlong) &(privKey->privateValue); // private big integer
1545N/A resultElements[1] = (jlong) &(privKey->publicValue); // encoded ec point
1545N/A
1545N/A // If the array is a copy then we must write back our changes
1545N/A if (isCopy == JNI_TRUE) {
1545N/A env->ReleaseLongArrayElements(result, resultElements, 0);
1545N/A }
1545N/A
1545N/Acleanup:
1545N/A {
1545N/A if (params_item.data)
1545N/A env->ReleaseByteArrayElements(encodedParams,
1545N/A (jbyte *) params_item.data, JNI_ABORT);
1545N/A
1545N/A if (ecparams)
1545N/A FreeECParams(ecparams, true);
1545N/A
1545N/A if (privKey) {
1545N/A FreeECParams(&privKey->ecParams, false);
1545N/A SECITEM_FreeItem(&privKey->version, B_FALSE);
1545N/A // Don't free privKey->privateValue and privKey->publicValue
1545N/A }
1545N/A
1545N/A if (pSeedBuffer)
1545N/A delete [] pSeedBuffer;
1545N/A }
1545N/A
1545N/A return result;
1545N/A}
1545N/A
1545N/A/*
1545N/A * Class: sun_security_ec_ECKeyPairGenerator
1545N/A * Method: getEncodedBytes
1545N/A * Signature: (J)[B
1545N/A */
1545N/AJNIEXPORT jbyteArray
1545N/AJNICALL Java_sun_security_ec_ECKeyPairGenerator_getEncodedBytes
1545N/A (JNIEnv *env, jclass clazz, jlong hSECItem)
1545N/A{
1545N/A SECItem *s = (SECItem *)hSECItem;
1545N/A jbyteArray jEncodedBytes = env->NewByteArray(s->len);
1545N/A
1545N/A // Copy bytes from a native SECItem buffer to Java byte array
1545N/A env->SetByteArrayRegion(jEncodedBytes, 0, s->len, (jbyte *)s->data);
1545N/A
1545N/A // Use B_FALSE to free only the SECItem->data
1545N/A SECITEM_FreeItem(s, B_FALSE);
1545N/A
1545N/A return jEncodedBytes;
1545N/A}
1545N/A
1545N/A/*
1545N/A * Class: sun_security_ec_ECDSASignature
1545N/A * Method: signDigest
1545N/A * Signature: ([B[B[B[B)[B
1545N/A */
1545N/AJNIEXPORT jbyteArray
1545N/AJNICALL Java_sun_security_ec_ECDSASignature_signDigest
1545N/A (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed)
1545N/A{
1545N/A jbyte* pDigestBuffer = NULL;
1545N/A jint jDigestLength = env->GetArrayLength(digest);
1545N/A jbyteArray jSignedDigest = NULL;
1545N/A
1545N/A SECItem signature_item;
1545N/A jbyte* pSignedDigestBuffer = NULL;
1545N/A jbyteArray temp;
1545N/A
1545N/A jint jSeedLength = env->GetArrayLength(seed);
1545N/A jbyte* pSeedBuffer = NULL;
1545N/A
1545N/A // Copy digest from Java to native buffer
1545N/A pDigestBuffer = new jbyte[jDigestLength];
1545N/A env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
1545N/A SECItem digest_item;
1545N/A digest_item.data = (unsigned char *) pDigestBuffer;
1545N/A digest_item.len = jDigestLength;
1545N/A
1545N/A ECPrivateKey privKey;
1545N/A
1545N/A // Initialize the ECParams struct
1545N/A ECParams *ecparams = NULL;
1545N/A SECKEYECParams params_item;
1545N/A params_item.len = env->GetArrayLength(encodedParams);
1545N/A params_item.data =
1545N/A (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
1545N/A
1545N/A // Fill a new ECParams using the supplied OID
1545N/A if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
1545N/A /* bad curve OID */
1545N/A ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A // Extract private key data
1545N/A privKey.ecParams = *ecparams; // struct assignment
1545N/A privKey.privateValue.len = env->GetArrayLength(privateKey);
1545N/A privKey.privateValue.data =
1545N/A (unsigned char *) env->GetByteArrayElements(privateKey, 0);
1545N/A
1545N/A // Prepare a buffer for the signature (twice the key length)
1545N/A pSignedDigestBuffer = new jbyte[ecparams->order.len * 2];
1545N/A signature_item.data = (unsigned char *) pSignedDigestBuffer;
1545N/A signature_item.len = ecparams->order.len * 2;
1545N/A
1545N/A // Copy seed from Java to native buffer
1545N/A pSeedBuffer = new jbyte[jSeedLength];
1545N/A env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
1545N/A
1545N/A // Sign the digest (using the supplied seed)
1545N/A if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
1545N/A (unsigned char *) pSeedBuffer, jSeedLength, 0) != SECSuccess) {
1545N/A ThrowException(env, KEY_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A // Create new byte array
1545N/A temp = env->NewByteArray(signature_item.len);
1545N/A
1545N/A // Copy data from native buffer
1545N/A env->SetByteArrayRegion(temp, 0, signature_item.len, pSignedDigestBuffer);
1545N/A jSignedDigest = temp;
1545N/A
1545N/Acleanup:
1545N/A {
1545N/A if (params_item.data)
1545N/A env->ReleaseByteArrayElements(encodedParams,
1545N/A (jbyte *) params_item.data, JNI_ABORT);
1545N/A
1545N/A if (pDigestBuffer)
1545N/A delete [] pDigestBuffer;
1545N/A
1545N/A if (pSignedDigestBuffer)
1545N/A delete [] pSignedDigestBuffer;
1545N/A
1545N/A if (pSeedBuffer)
1545N/A delete [] pSeedBuffer;
1545N/A
1545N/A if (ecparams)
1545N/A FreeECParams(ecparams, true);
1545N/A }
1545N/A
1545N/A return jSignedDigest;
1545N/A}
1545N/A
1545N/A/*
1545N/A * Class: sun_security_ec_ECDSASignature
1545N/A * Method: verifySignedDigest
1545N/A * Signature: ([B[B[B[B)Z
1545N/A */
1545N/AJNIEXPORT jboolean
1545N/AJNICALL Java_sun_security_ec_ECDSASignature_verifySignedDigest
1545N/A (JNIEnv *env, jclass clazz, jbyteArray signedDigest, jbyteArray digest, jbyteArray publicKey, jbyteArray encodedParams)
1545N/A{
1545N/A jboolean isValid = false;
1545N/A
1545N/A // Copy signedDigest from Java to native buffer
1545N/A jbyte* pSignedDigestBuffer = NULL;
1545N/A jint jSignedDigestLength = env->GetArrayLength(signedDigest);
1545N/A pSignedDigestBuffer = new jbyte[jSignedDigestLength];
1545N/A env->GetByteArrayRegion(signedDigest, 0, jSignedDigestLength,
1545N/A pSignedDigestBuffer);
1545N/A SECItem signature_item;
1545N/A signature_item.data = (unsigned char *) pSignedDigestBuffer;
1545N/A signature_item.len = jSignedDigestLength;
1545N/A
1545N/A // Copy digest from Java to native buffer
1545N/A jbyte* pDigestBuffer = NULL;
1545N/A jint jDigestLength = env->GetArrayLength(digest);
1545N/A pDigestBuffer = new jbyte[jDigestLength];
1545N/A env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
1545N/A SECItem digest_item;
1545N/A digest_item.data = (unsigned char *) pDigestBuffer;
1545N/A digest_item.len = jDigestLength;
1545N/A
1545N/A // Extract public key data
1545N/A ECPublicKey pubKey;
1545N/A pubKey.publicValue.data = NULL;
1545N/A ECParams *ecparams = NULL;
1545N/A SECKEYECParams params_item;
1545N/A
1545N/A // Initialize the ECParams struct
1545N/A params_item.len = env->GetArrayLength(encodedParams);
1545N/A params_item.data =
1545N/A (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
1545N/A
1545N/A // Fill a new ECParams using the supplied OID
1545N/A if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
1545N/A /* bad curve OID */
1545N/A ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A pubKey.ecParams = *ecparams; // struct assignment
1545N/A pubKey.publicValue.len = env->GetArrayLength(publicKey);
1545N/A pubKey.publicValue.data =
1545N/A (unsigned char *) env->GetByteArrayElements(publicKey, 0);
1545N/A
1545N/A if (ECDSA_VerifyDigest(&pubKey, &signature_item, &digest_item, 0)
1545N/A != SECSuccess) {
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A isValid = true;
1545N/A
1545N/Acleanup:
1545N/A {
1545N/A if (params_item.data)
1545N/A env->ReleaseByteArrayElements(encodedParams,
1545N/A (jbyte *) params_item.data, JNI_ABORT);
1545N/A
1545N/A if (pubKey.publicValue.data)
1545N/A env->ReleaseByteArrayElements(publicKey,
1545N/A (jbyte *) pubKey.publicValue.data, JNI_ABORT);
1545N/A
1545N/A if (ecparams)
1545N/A FreeECParams(ecparams, true);
1545N/A
1545N/A if (pSignedDigestBuffer)
1545N/A delete [] pSignedDigestBuffer;
1545N/A
1545N/A if (pDigestBuffer)
1545N/A delete [] pDigestBuffer;
1545N/A }
1545N/A
1545N/A return isValid;
1545N/A}
1545N/A
1545N/A/*
1545N/A * Class: sun_security_ec_ECDHKeyAgreement
1545N/A * Method: deriveKey
1545N/A * Signature: ([B[B[B)[B
1545N/A */
1545N/AJNIEXPORT jbyteArray
1545N/AJNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
1545N/A (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams)
1545N/A{
1545N/A jbyteArray jSecret = NULL;
1545N/A
1545N/A // Extract private key value
1545N/A SECItem privateValue_item;
1545N/A privateValue_item.len = env->GetArrayLength(privateKey);
1545N/A privateValue_item.data =
1545N/A (unsigned char *) env->GetByteArrayElements(privateKey, 0);
1545N/A
1545N/A // Extract public key value
1545N/A SECItem publicValue_item;
1545N/A publicValue_item.len = env->GetArrayLength(publicKey);
1545N/A publicValue_item.data =
1545N/A (unsigned char *) env->GetByteArrayElements(publicKey, 0);
1545N/A
1545N/A // Initialize the ECParams struct
1545N/A ECParams *ecparams = NULL;
1545N/A SECKEYECParams params_item;
1545N/A params_item.len = env->GetArrayLength(encodedParams);
1545N/A params_item.data =
1545N/A (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
1545N/A
1545N/A // Fill a new ECParams using the supplied OID
1545N/A if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
1545N/A /* bad curve OID */
1545N/A ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A // Prepare a buffer for the secret
1545N/A SECItem secret_item;
1545N/A secret_item.data = NULL;
1545N/A secret_item.len = ecparams->order.len * 2;
1545N/A
1545N/A if (ECDH_Derive(&publicValue_item, ecparams, &privateValue_item, B_FALSE,
1545N/A &secret_item, 0) != SECSuccess) {
1545N/A ThrowException(env, ILLEGAL_STATE_EXCEPTION);
1545N/A goto cleanup;
1545N/A }
1545N/A
1545N/A // Create new byte array
1545N/A jSecret = env->NewByteArray(secret_item.len);
1545N/A
1545N/A // Copy bytes from the SECItem buffer to a Java byte array
1545N/A env->SetByteArrayRegion(jSecret, 0, secret_item.len,
1545N/A (jbyte *)secret_item.data);
1545N/A
1545N/A // Free the SECItem data buffer
1545N/A SECITEM_FreeItem(&secret_item, B_FALSE);
1545N/A
1545N/Acleanup:
1545N/A {
1545N/A if (privateValue_item.data)
1545N/A env->ReleaseByteArrayElements(privateKey,
1545N/A (jbyte *) privateValue_item.data, JNI_ABORT);
1545N/A
1545N/A if (publicValue_item.data)
1545N/A env->ReleaseByteArrayElements(publicKey,
1545N/A (jbyte *) publicValue_item.data, JNI_ABORT);
1545N/A
1545N/A if (params_item.data)
1545N/A env->ReleaseByteArrayElements(encodedParams,
1545N/A (jbyte *) params_item.data, JNI_ABORT);
1545N/A
1545N/A if (ecparams)
1545N/A FreeECParams(ecparams, true);
1545N/A }
1545N/A
1545N/A return jSecret;
1545N/A}
1545N/A
1545N/A} /* extern "C" */