1 /*
2  * Copyright (c) 2005, 2019, 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 sun.security.mscapi;
27 
28 import sun.security.util.KeyUtil;
29 import sun.security.util.Length;
30 
31 import java.math.BigInteger;
32 import java.security.Key;
33 import java.security.interfaces.ECPrivateKey;
34 import java.security.interfaces.ECPublicKey;
35 
36 /**
37  * The handle for a key using the Microsoft Crypto API.
38  *
39  * @see CPrivateKey
40  * @see CPublicKey
41  *
42  * @since 1.6
43  * @author  Stanley Man-Kit Ho
44  */
45 abstract class CKey implements Key, Length {
46     private static final long serialVersionUID = -1088859394025049194L;
47 
48     static class NativeHandles {
49 
50         long hCryptProv = 0;
51         long hCryptKey = 0;
52 
NativeHandles(long hCryptProv, long hCryptKey)53         public NativeHandles(long hCryptProv, long hCryptKey) {
54             this.hCryptProv = hCryptProv;
55             this.hCryptKey = hCryptKey;
56         }
57 
58         @SuppressWarnings("deprecation")
finalize()59         protected void finalize() throws Throwable {
60             try {
61                 synchronized(this) {
62                     cleanUp(hCryptProv, hCryptKey);
63                     hCryptProv = 0;
64                     hCryptKey = 0;
65                 }
66             } finally {
67                 super.finalize();
68             }
69         }
70     }
71 
72     protected final NativeHandles handles;
73 
74     protected final int keyLength;
75 
76     protected final String algorithm;
77 
CKey(String algorithm, NativeHandles handles, int keyLength)78     protected CKey(String algorithm, NativeHandles handles, int keyLength) {
79         this.algorithm = algorithm;
80         this.handles = handles;
81         this.keyLength = keyLength;
82     }
83 
84     // Native method to cleanup the key handle.
cleanUp(long hCryptProv, long hCryptKey)85     private native static void cleanUp(long hCryptProv, long hCryptKey);
86 
87     @Override
length()88     public int length() {
89         return keyLength;
90     }
91 
getHCryptKey()92     public long getHCryptKey() {
93         return handles.hCryptKey;
94     }
95 
getHCryptProvider()96     public long getHCryptProvider() {
97         return handles.hCryptProv;
98     }
99 
getAlgorithm()100     public String getAlgorithm() {
101         return algorithm;
102     }
103 
getContainerName(long hCryptProv)104     protected native static String getContainerName(long hCryptProv);
105 
getKeyType(long hCryptKey)106     protected native static String getKeyType(long hCryptKey);
107 
108     // This java method generates EC BLOBs for public key or private key.
109     // See https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/ns-bcrypt-_bcrypt_ecckey_blob
generateECBlob(Key k)110     static byte[] generateECBlob(Key k) {
111 
112         int keyBitLength = KeyUtil.getKeySize(k);
113         int keyLen = (keyBitLength + 7) / 8;
114         boolean isPrivate = k instanceof ECPrivateKey;
115 
116         byte[] keyBlob = new byte[8 + keyLen * (isPrivate ? 3 : 2)];
117         keyBlob[0] = 'E';
118         keyBlob[1] = 'C';
119         keyBlob[2] = 'S';
120         if (isPrivate) {
121             keyBlob[3] = (byte) (keyBitLength == 256 ? '2'
122                     : (keyBitLength == 384 ? '4' : '6'));
123         } else {
124             keyBlob[3] = (byte) (keyBitLength == 256 ? '1'
125                     : (keyBitLength == 384 ? '3' : '5'));
126         }
127         BigInteger x;
128         BigInteger y;
129         // Fill the array in reverse order (s -> y -> x -> len) in case
130         // one BigInteger encoding has an extra 0 at the beginning
131         if (isPrivate) {
132             // We can keep X and Y zero and it still works
133             ECPrivateKey prk = (ECPrivateKey)k;
134             BigInteger s = prk.getS();
135             byte[] bs = s.toByteArray();
136             System.arraycopy(
137                     bs, 0,
138                     keyBlob, 8 + keyLen + keyLen + keyLen - bs.length,
139                     bs.length);
140         } else {
141             ECPublicKey puk = (ECPublicKey)k;
142             x = puk.getW().getAffineX();
143             y = puk.getW().getAffineY();
144             byte[] by = y.toByteArray();
145             System.arraycopy(by, 0, keyBlob, 8 + keyLen + keyLen - by.length,
146                     by.length);
147             byte[] bx = x.toByteArray();
148             System.arraycopy(bx, 0, keyBlob, 8 + keyLen - bx.length, bx.length);
149         }
150         keyBlob[4] = (byte) keyLen;
151         keyBlob[5] = keyBlob[6] = keyBlob[7] = 0;
152         return keyBlob;
153     }
154 }
155