jdk/src/share/native/sun/security/ec/ECC_JNI.cpp
changeset 3492 e549cea58864
child 3863 8e0f58b1c072
equal deleted inserted replaced
3480:c197e38bf15a 3492:e549cea58864
       
     1 /*
       
     2  * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 #include <jni.h>
       
    27 #include "ecc_impl.h"
       
    28 
       
    29 #define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
       
    30 #define INVALID_ALGORITHM_PARAMETER_EXCEPTION \
       
    31         "java/security/InvalidAlgorithmParameterException"
       
    32 #define INVALID_PARAMETER_EXCEPTION \
       
    33         "java/security/InvalidParameterException"
       
    34 #define KEY_EXCEPTION   "java/security/KeyException"
       
    35 
       
    36 extern "C" {
       
    37 
       
    38 /*
       
    39  * Throws an arbitrary Java exception.
       
    40  */
       
    41 void ThrowException(JNIEnv *env, char *exceptionName)
       
    42 {
       
    43     jclass exceptionClazz = env->FindClass(exceptionName);
       
    44     env->ThrowNew(exceptionClazz, NULL);
       
    45 }
       
    46 
       
    47 /*
       
    48  * Deep free of the ECParams struct
       
    49  */
       
    50 void FreeECParams(ECParams *ecparams, jboolean freeStruct)
       
    51 {
       
    52     // Use B_FALSE to free the SECItem->data element, but not the SECItem itself
       
    53     // Use B_TRUE to free both
       
    54 
       
    55     SECITEM_FreeItem(&ecparams->fieldID.u.prime, B_FALSE);
       
    56     SECITEM_FreeItem(&ecparams->curve.a, B_FALSE);
       
    57     SECITEM_FreeItem(&ecparams->curve.b, B_FALSE);
       
    58     SECITEM_FreeItem(&ecparams->curve.seed, B_FALSE);
       
    59     SECITEM_FreeItem(&ecparams->base, B_FALSE);
       
    60     SECITEM_FreeItem(&ecparams->order, B_FALSE);
       
    61     SECITEM_FreeItem(&ecparams->DEREncoding, B_FALSE);
       
    62     SECITEM_FreeItem(&ecparams->curveOID, B_FALSE);
       
    63     if (freeStruct)
       
    64         free(ecparams);
       
    65 }
       
    66 
       
    67 /*
       
    68  * Class:     sun_security_ec_ECKeyPairGenerator
       
    69  * Method:    generateECKeyPair
       
    70  * Signature: (I[B[B)[J
       
    71  */
       
    72 JNIEXPORT jlongArray
       
    73 JNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
       
    74   (JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed)
       
    75 {
       
    76     ECPrivateKey *privKey;      /* contains both public and private values */
       
    77     ECParams *ecparams = NULL;
       
    78     SECKEYECParams params_item;
       
    79     jint jSeedLength;
       
    80     jbyte* pSeedBuffer = NULL;
       
    81     jlongArray result = NULL;
       
    82     jlong* resultElements = NULL;
       
    83 
       
    84     // Initialize the ECParams struct
       
    85     params_item.len = env->GetArrayLength(encodedParams);
       
    86     params_item.data =
       
    87         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
    88 
       
    89     // Fill a new ECParams using the supplied OID
       
    90     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
    91         /* bad curve OID */
       
    92         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
    93         goto cleanup;
       
    94     }
       
    95 
       
    96     // Copy seed from Java to native buffer
       
    97     jSeedLength = env->GetArrayLength(seed);
       
    98     pSeedBuffer = new jbyte[jSeedLength];
       
    99     env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
       
   100 
       
   101     // Generate the new keypair (using the supplied seed)
       
   102     if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer,
       
   103         jSeedLength, 0) != SECSuccess) {
       
   104         ThrowException(env, KEY_EXCEPTION);
       
   105         goto cleanup;
       
   106     }
       
   107 
       
   108     jboolean isCopy;
       
   109     result = env->NewLongArray(2);
       
   110     resultElements = env->GetLongArrayElements(result, &isCopy);
       
   111 
       
   112     resultElements[0] = (jlong) &(privKey->privateValue); // private big integer
       
   113     resultElements[1] = (jlong) &(privKey->publicValue); // encoded ec point
       
   114 
       
   115     // If the array is a copy then we must write back our changes
       
   116     if (isCopy == JNI_TRUE) {
       
   117         env->ReleaseLongArrayElements(result, resultElements, 0);
       
   118     }
       
   119 
       
   120 cleanup:
       
   121     {
       
   122         if (params_item.data)
       
   123             env->ReleaseByteArrayElements(encodedParams,
       
   124                 (jbyte *) params_item.data, JNI_ABORT);
       
   125 
       
   126         if (ecparams)
       
   127             FreeECParams(ecparams, true);
       
   128 
       
   129         if (privKey) {
       
   130             FreeECParams(&privKey->ecParams, false);
       
   131             SECITEM_FreeItem(&privKey->version, B_FALSE);
       
   132             // Don't free privKey->privateValue and privKey->publicValue
       
   133         }
       
   134 
       
   135         if (pSeedBuffer)
       
   136             delete [] pSeedBuffer;
       
   137     }
       
   138 
       
   139     return result;
       
   140 }
       
   141 
       
   142 /*
       
   143  * Class:     sun_security_ec_ECKeyPairGenerator
       
   144  * Method:    getEncodedBytes
       
   145  * Signature: (J)[B
       
   146  */
       
   147 JNIEXPORT jbyteArray
       
   148 JNICALL Java_sun_security_ec_ECKeyPairGenerator_getEncodedBytes
       
   149   (JNIEnv *env, jclass clazz, jlong hSECItem)
       
   150 {
       
   151     SECItem *s = (SECItem *)hSECItem;
       
   152     jbyteArray jEncodedBytes = env->NewByteArray(s->len);
       
   153 
       
   154     // Copy bytes from a native SECItem buffer to Java byte array
       
   155     env->SetByteArrayRegion(jEncodedBytes, 0, s->len, (jbyte *)s->data);
       
   156 
       
   157     // Use B_FALSE to free only the SECItem->data
       
   158     SECITEM_FreeItem(s, B_FALSE);
       
   159 
       
   160     return jEncodedBytes;
       
   161 }
       
   162 
       
   163 /*
       
   164  * Class:     sun_security_ec_ECDSASignature
       
   165  * Method:    signDigest
       
   166  * Signature: ([B[B[B[B)[B
       
   167  */
       
   168 JNIEXPORT jbyteArray
       
   169 JNICALL Java_sun_security_ec_ECDSASignature_signDigest
       
   170   (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed)
       
   171 {
       
   172     jbyte* pDigestBuffer = NULL;
       
   173     jint jDigestLength = env->GetArrayLength(digest);
       
   174     jbyteArray jSignedDigest = NULL;
       
   175 
       
   176     SECItem signature_item;
       
   177     jbyte* pSignedDigestBuffer = NULL;
       
   178     jbyteArray temp;
       
   179 
       
   180     jint jSeedLength = env->GetArrayLength(seed);
       
   181     jbyte* pSeedBuffer = NULL;
       
   182 
       
   183     // Copy digest from Java to native buffer
       
   184     pDigestBuffer = new jbyte[jDigestLength];
       
   185     env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
       
   186     SECItem digest_item;
       
   187     digest_item.data = (unsigned char *) pDigestBuffer;
       
   188     digest_item.len = jDigestLength;
       
   189 
       
   190     ECPrivateKey privKey;
       
   191 
       
   192     // Initialize the ECParams struct
       
   193     ECParams *ecparams = NULL;
       
   194     SECKEYECParams params_item;
       
   195     params_item.len = env->GetArrayLength(encodedParams);
       
   196     params_item.data =
       
   197         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   198 
       
   199     // Fill a new ECParams using the supplied OID
       
   200     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   201         /* bad curve OID */
       
   202         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   203         goto cleanup;
       
   204     }
       
   205 
       
   206     // Extract private key data
       
   207     privKey.ecParams = *ecparams; // struct assignment
       
   208     privKey.privateValue.len = env->GetArrayLength(privateKey);
       
   209     privKey.privateValue.data =
       
   210         (unsigned char *) env->GetByteArrayElements(privateKey, 0);
       
   211 
       
   212     // Prepare a buffer for the signature (twice the key length)
       
   213     pSignedDigestBuffer = new jbyte[ecparams->order.len * 2];
       
   214     signature_item.data = (unsigned char *) pSignedDigestBuffer;
       
   215     signature_item.len = ecparams->order.len * 2;
       
   216 
       
   217     // Copy seed from Java to native buffer
       
   218     pSeedBuffer = new jbyte[jSeedLength];
       
   219     env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
       
   220 
       
   221     // Sign the digest (using the supplied seed)
       
   222     if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
       
   223         (unsigned char *) pSeedBuffer, jSeedLength, 0) != SECSuccess) {
       
   224         ThrowException(env, KEY_EXCEPTION);
       
   225         goto cleanup;
       
   226     }
       
   227 
       
   228     // Create new byte array
       
   229     temp = env->NewByteArray(signature_item.len);
       
   230 
       
   231     // Copy data from native buffer
       
   232     env->SetByteArrayRegion(temp, 0, signature_item.len, pSignedDigestBuffer);
       
   233     jSignedDigest = temp;
       
   234 
       
   235 cleanup:
       
   236     {
       
   237         if (params_item.data)
       
   238             env->ReleaseByteArrayElements(encodedParams,
       
   239                 (jbyte *) params_item.data, JNI_ABORT);
       
   240 
       
   241         if (pDigestBuffer)
       
   242             delete [] pDigestBuffer;
       
   243 
       
   244         if (pSignedDigestBuffer)
       
   245             delete [] pSignedDigestBuffer;
       
   246 
       
   247         if (pSeedBuffer)
       
   248             delete [] pSeedBuffer;
       
   249 
       
   250         if (ecparams)
       
   251             FreeECParams(ecparams, true);
       
   252     }
       
   253 
       
   254     return jSignedDigest;
       
   255 }
       
   256 
       
   257 /*
       
   258  * Class:     sun_security_ec_ECDSASignature
       
   259  * Method:    verifySignedDigest
       
   260  * Signature: ([B[B[B[B)Z
       
   261  */
       
   262 JNIEXPORT jboolean
       
   263 JNICALL Java_sun_security_ec_ECDSASignature_verifySignedDigest
       
   264   (JNIEnv *env, jclass clazz, jbyteArray signedDigest, jbyteArray digest, jbyteArray publicKey, jbyteArray encodedParams)
       
   265 {
       
   266     jboolean isValid = false;
       
   267 
       
   268     // Copy signedDigest from Java to native buffer
       
   269     jbyte* pSignedDigestBuffer = NULL;
       
   270     jint jSignedDigestLength = env->GetArrayLength(signedDigest);
       
   271     pSignedDigestBuffer = new jbyte[jSignedDigestLength];
       
   272     env->GetByteArrayRegion(signedDigest, 0, jSignedDigestLength,
       
   273         pSignedDigestBuffer);
       
   274     SECItem signature_item;
       
   275     signature_item.data = (unsigned char *) pSignedDigestBuffer;
       
   276     signature_item.len = jSignedDigestLength;
       
   277 
       
   278     // Copy digest from Java to native buffer
       
   279     jbyte* pDigestBuffer = NULL;
       
   280     jint jDigestLength = env->GetArrayLength(digest);
       
   281     pDigestBuffer = new jbyte[jDigestLength];
       
   282     env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
       
   283     SECItem digest_item;
       
   284     digest_item.data = (unsigned char *) pDigestBuffer;
       
   285     digest_item.len = jDigestLength;
       
   286 
       
   287     // Extract public key data
       
   288     ECPublicKey pubKey;
       
   289     pubKey.publicValue.data = NULL;
       
   290     ECParams *ecparams = NULL;
       
   291     SECKEYECParams params_item;
       
   292 
       
   293     // Initialize the ECParams struct
       
   294     params_item.len = env->GetArrayLength(encodedParams);
       
   295     params_item.data =
       
   296         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   297 
       
   298     // Fill a new ECParams using the supplied OID
       
   299     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   300         /* bad curve OID */
       
   301         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   302         goto cleanup;
       
   303     }
       
   304     pubKey.ecParams = *ecparams; // struct assignment
       
   305     pubKey.publicValue.len = env->GetArrayLength(publicKey);
       
   306     pubKey.publicValue.data =
       
   307         (unsigned char *) env->GetByteArrayElements(publicKey, 0);
       
   308 
       
   309     if (ECDSA_VerifyDigest(&pubKey, &signature_item, &digest_item, 0)
       
   310             != SECSuccess) {
       
   311         goto cleanup;
       
   312     }
       
   313 
       
   314     isValid = true;
       
   315 
       
   316 cleanup:
       
   317     {
       
   318         if (params_item.data)
       
   319             env->ReleaseByteArrayElements(encodedParams,
       
   320                 (jbyte *) params_item.data, JNI_ABORT);
       
   321 
       
   322         if (pubKey.publicValue.data)
       
   323             env->ReleaseByteArrayElements(publicKey,
       
   324                 (jbyte *) pubKey.publicValue.data, JNI_ABORT);
       
   325 
       
   326         if (ecparams)
       
   327             FreeECParams(ecparams, true);
       
   328 
       
   329         if (pSignedDigestBuffer)
       
   330             delete [] pSignedDigestBuffer;
       
   331 
       
   332         if (pDigestBuffer)
       
   333             delete [] pDigestBuffer;
       
   334     }
       
   335 
       
   336     return isValid;
       
   337 }
       
   338 
       
   339 /*
       
   340  * Class:     sun_security_ec_ECDHKeyAgreement
       
   341  * Method:    deriveKey
       
   342  * Signature: ([B[B[B)[B
       
   343  */
       
   344 JNIEXPORT jbyteArray
       
   345 JNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
       
   346   (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams)
       
   347 {
       
   348     jbyteArray jSecret = NULL;
       
   349 
       
   350     // Extract private key value
       
   351     SECItem privateValue_item;
       
   352     privateValue_item.len = env->GetArrayLength(privateKey);
       
   353     privateValue_item.data =
       
   354             (unsigned char *) env->GetByteArrayElements(privateKey, 0);
       
   355 
       
   356     // Extract public key value
       
   357     SECItem publicValue_item;
       
   358     publicValue_item.len = env->GetArrayLength(publicKey);
       
   359     publicValue_item.data =
       
   360         (unsigned char *) env->GetByteArrayElements(publicKey, 0);
       
   361 
       
   362     // Initialize the ECParams struct
       
   363     ECParams *ecparams = NULL;
       
   364     SECKEYECParams params_item;
       
   365     params_item.len = env->GetArrayLength(encodedParams);
       
   366     params_item.data =
       
   367         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   368 
       
   369     // Fill a new ECParams using the supplied OID
       
   370     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   371         /* bad curve OID */
       
   372         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   373         goto cleanup;
       
   374     }
       
   375 
       
   376     // Prepare a buffer for the secret
       
   377     SECItem secret_item;
       
   378     secret_item.data = NULL;
       
   379     secret_item.len = ecparams->order.len * 2;
       
   380 
       
   381     if (ECDH_Derive(&publicValue_item, ecparams, &privateValue_item, B_FALSE,
       
   382         &secret_item, 0) != SECSuccess) {
       
   383         ThrowException(env, ILLEGAL_STATE_EXCEPTION);
       
   384         goto cleanup;
       
   385     }
       
   386 
       
   387     // Create new byte array
       
   388     jSecret = env->NewByteArray(secret_item.len);
       
   389 
       
   390     // Copy bytes from the SECItem buffer to a Java byte array
       
   391     env->SetByteArrayRegion(jSecret, 0, secret_item.len,
       
   392         (jbyte *)secret_item.data);
       
   393 
       
   394     // Free the SECItem data buffer
       
   395     SECITEM_FreeItem(&secret_item, B_FALSE);
       
   396 
       
   397 cleanup:
       
   398     {
       
   399         if (privateValue_item.data)
       
   400             env->ReleaseByteArrayElements(privateKey,
       
   401                 (jbyte *) privateValue_item.data, JNI_ABORT);
       
   402 
       
   403         if (publicValue_item.data)
       
   404             env->ReleaseByteArrayElements(publicKey,
       
   405                 (jbyte *) publicValue_item.data, JNI_ABORT);
       
   406 
       
   407         if (params_item.data)
       
   408             env->ReleaseByteArrayElements(encodedParams,
       
   409                 (jbyte *) params_item.data, JNI_ABORT);
       
   410 
       
   411         if (ecparams)
       
   412             FreeECParams(ecparams, true);
       
   413     }
       
   414 
       
   415     return jSecret;
       
   416 }
       
   417 
       
   418 } /* extern "C" */