src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigestMD.java
changeset 47216 71c04702a3d5
parent 37909 38b1efe33344
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2016, Oracle and/or its affiliates. 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.oracle.security.ucrypto;
       
    27 
       
    28 import java.lang.ref.*;
       
    29 
       
    30 import java.io.ByteArrayOutputStream;
       
    31 import java.util.*;
       
    32 import java.util.concurrent.ConcurrentSkipListSet;
       
    33 import java.security.*;
       
    34 
       
    35 /**
       
    36  * MessageDigest implementation class for libMD API. This class currently supports
       
    37  * MD5, SHA1, SHA256, SHA384, and SHA512
       
    38  *
       
    39  * @since 9
       
    40  */
       
    41 public abstract class NativeDigestMD extends MessageDigestSpi
       
    42         implements Cloneable {
       
    43 
       
    44     private static final int MECH_MD5 = 1;
       
    45     private static final int MECH_SHA1 = 2;
       
    46     private static final int MECH_SHA256 = 3;
       
    47     private static final int MECH_SHA224 = 4;
       
    48     private static final int MECH_SHA384 = 5;
       
    49     private static final int MECH_SHA512 = 6;
       
    50 
       
    51     private final int digestLen;
       
    52     private final int mech;
       
    53 
       
    54     // field for ensuring native memory is freed
       
    55     private DigestContextRef pCtxt = null;
       
    56 
       
    57     private static class DigestContextRef extends PhantomReference<NativeDigestMD>
       
    58         implements Comparable<DigestContextRef> {
       
    59 
       
    60         private static ReferenceQueue<NativeDigestMD> refQueue =
       
    61             new ReferenceQueue<NativeDigestMD>();
       
    62 
       
    63         // Needed to keep these references from being GC'ed until when their
       
    64         // referents are GC'ed so we can do post-mortem processing
       
    65         private static Set<DigestContextRef> refList =
       
    66             new ConcurrentSkipListSet<DigestContextRef>();
       
    67             //            Collections.synchronizedSortedSet(new TreeSet<DigestContextRef>());
       
    68 
       
    69         private final long id;
       
    70         private final int mech;
       
    71 
       
    72         private static void drainRefQueueBounded() {
       
    73             while (true) {
       
    74                 DigestContextRef next = (DigestContextRef) refQueue.poll();
       
    75                 if (next == null) break;
       
    76                 next.dispose(true);
       
    77             }
       
    78         }
       
    79 
       
    80         DigestContextRef(NativeDigestMD nc, long id, int mech) {
       
    81             super(nc, refQueue);
       
    82             this.id = id;
       
    83             this.mech = mech;
       
    84             refList.add(this);
       
    85             UcryptoProvider.debug("Resource: track Digest Ctxt " + this.id);
       
    86             drainRefQueueBounded();
       
    87         }
       
    88 
       
    89         public int compareTo(DigestContextRef other) {
       
    90             if (this.id == other.id) {
       
    91                 return 0;
       
    92             } else {
       
    93                 return (this.id < other.id) ? -1 : 1;
       
    94             }
       
    95         }
       
    96 
       
    97         void dispose(boolean needFree) {
       
    98             refList.remove(this);
       
    99             try {
       
   100                 if (needFree) {
       
   101                     UcryptoProvider.debug("Resource: free Digest Ctxt " + this.id);
       
   102                     NativeDigestMD.nativeFree(mech, id);
       
   103                 } else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id);
       
   104             } finally {
       
   105                 this.clear();
       
   106             }
       
   107         }
       
   108     }
       
   109 
       
   110     NativeDigestMD(int mech, int digestLen) {
       
   111         this.digestLen = digestLen;
       
   112         this.mech = mech;
       
   113     }
       
   114 
       
   115     // see JCA spec
       
   116     protected int engineGetDigestLength() {
       
   117         return digestLen;
       
   118     }
       
   119 
       
   120     // see JCA spec
       
   121     protected synchronized void engineReset() {
       
   122         if (pCtxt != null) {
       
   123             pCtxt.dispose(true);
       
   124             pCtxt = null;
       
   125         }
       
   126     }
       
   127 
       
   128     // see JCA spec
       
   129     protected synchronized byte[] engineDigest() {
       
   130         byte[] digest = new byte[digestLen];
       
   131         try {
       
   132             int len = engineDigest(digest, 0, digestLen);
       
   133             if (len != digestLen) {
       
   134                 throw new UcryptoException("Digest length mismatch." +
       
   135                     " Len: " + len + ". digestLen: " + digestLen);
       
   136             }
       
   137             return digest;
       
   138         } catch (DigestException de) {
       
   139             throw new UcryptoException("Internal error", de);
       
   140         }
       
   141     }
       
   142 
       
   143     // see JCA spec
       
   144     protected synchronized int engineDigest(byte[] out, int ofs, int len)
       
   145             throws DigestException {
       
   146         if (len < digestLen) {
       
   147             throw new DigestException("Output buffer must be at least " +
       
   148                           digestLen + " bytes long. Got: " + len);
       
   149         }
       
   150         if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) {
       
   151             throw new DigestException("Buffer too short to store digest. " +
       
   152                 "ofs: " + ofs + ". len: " + len + ". out.length: " + out.length);
       
   153         }
       
   154 
       
   155         if (pCtxt == null) {
       
   156             pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
       
   157         }
       
   158         try {
       
   159             int status = nativeDigest(mech, pCtxt.id, out, ofs, digestLen);
       
   160             if (status != 0) {
       
   161                 throw new DigestException("Internal error: " + status);
       
   162             }
       
   163         } finally {
       
   164             pCtxt.dispose(false);
       
   165             pCtxt = null;
       
   166         }
       
   167         return digestLen;
       
   168     }
       
   169 
       
   170     // see JCA spec
       
   171     protected synchronized void engineUpdate(byte in) {
       
   172         byte[] temp = { in };
       
   173         engineUpdate(temp, 0, 1);
       
   174     }
       
   175 
       
   176     // see JCA spec
       
   177     protected synchronized void engineUpdate(byte[] in, int ofs, int len) {
       
   178         if (len == 0) {
       
   179             return;
       
   180         }
       
   181         if ((ofs < 0) || (len < 0) || (ofs > in.length - len)) {
       
   182             throw new ArrayIndexOutOfBoundsException("ofs: " + ofs + ". len: "
       
   183                 + len + ". in.length: " + in.length);
       
   184         }
       
   185         if (pCtxt == null) {
       
   186             pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
       
   187         }
       
   188         nativeUpdate(mech, pCtxt.id, in, ofs, len);
       
   189     }
       
   190 
       
   191     /**
       
   192      * Clone this digest.
       
   193      */
       
   194     public synchronized Object clone() throws CloneNotSupportedException {
       
   195         NativeDigestMD copy = (NativeDigestMD) super.clone();
       
   196         // re-work the fields that cannot be copied over
       
   197         if (pCtxt != null) {
       
   198             copy.pCtxt = new DigestContextRef(this, nativeClone(mech, pCtxt.id), mech);
       
   199         }
       
   200         return copy;
       
   201     }
       
   202 
       
   203     // return pointer to the context
       
   204     protected static final native long nativeInit(int mech);
       
   205     // return status code; always 0
       
   206     protected static final native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen);
       
   207     // return status code; always 0
       
   208     protected static final native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen);
       
   209     // return pointer to the duplicated context
       
   210     protected static final native long nativeClone(int mech, long pCtxt);
       
   211     // free the specified context
       
   212     private static final native void nativeFree(int mech, long id);
       
   213 
       
   214 
       
   215     public static final class MD5 extends NativeDigestMD {
       
   216         public MD5() {
       
   217             super(MECH_MD5, 16);
       
   218         }
       
   219     }
       
   220 
       
   221     public static final class SHA1 extends NativeDigestMD {
       
   222         public SHA1() {
       
   223             super(MECH_SHA1, 20);
       
   224         }
       
   225     }
       
   226 
       
   227     public static final class SHA256 extends NativeDigestMD {
       
   228         public SHA256() {
       
   229             super(MECH_SHA256, 32);
       
   230         }
       
   231     }
       
   232 
       
   233 
       
   234     public static final class SHA384 extends NativeDigestMD {
       
   235         public SHA384() {
       
   236             super(MECH_SHA384, 48);
       
   237         }
       
   238     }
       
   239 
       
   240 
       
   241     public static final class SHA512 extends NativeDigestMD {
       
   242         public SHA512() {
       
   243             super(MECH_SHA512, 64);
       
   244         }
       
   245     }
       
   246 }