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