1 /*
2 * Copyright (c) 1997, 2017, 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.provider;
27
28 import java.io.IOException;
29 import java.io.UnsupportedEncodingException;
30 import java.security.Key;
31 import java.security.KeyStoreException;
32 import java.security.MessageDigest;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.SecureRandom;
35 import java.security.UnrecoverableKeyException;
36 import java.util.*;
37
38 import jdk.internal.ref.CleanerFactory;
39 import sun.security.pkcs.PKCS8Key;
40 import sun.security.pkcs.EncryptedPrivateKeyInfo;
41 import sun.security.x509.AlgorithmId;
42 import sun.security.util.ObjectIdentifier;
43 import sun.security.util.DerValue;
44
45 /**
46 * This is an implementation of a Sun proprietary, exportable algorithm
47 * intended for use when protecting (or recovering the cleartext version of)
48 * sensitive keys.
49 * This algorithm is not intended as a general purpose cipher.
50 *
51 * This is how the algorithm works for key protection:
52 *
53 * p - user password
54 * s - random salt
55 * X - xor key
56 * P - to-be-protected key
57 * Y - protected key
58 * R - what gets stored in the keystore
103
104 final class KeyProtector {
105
106 private static final int SALT_LEN = 20; // the salt length
107 private static final String DIGEST_ALG = "SHA";
108 private static final int DIGEST_LEN = 20;
109
110 // defined by JavaSoft
111 private static final String KEY_PROTECTOR_OID = "1.3.6.1.4.1.42.2.17.1.1";
112
113 // The password used for protecting/recovering keys passed through this
114 // key protector. We store it as a byte array, so that we can digest it.
115 private byte[] passwdBytes;
116
117 private MessageDigest md;
118
119
120 /**
121 * Creates an instance of this class, and initializes it with the given
122 * password.
123 *
124 * <p>The password is expected to be in printable ASCII.
125 * Normal rules for good password selection apply: at least
126 * seven characters, mixed case, with punctuation encouraged.
127 * Phrases or words which are easily guessed, for example by
128 * being found in dictionaries, are bad.
129 */
130 public KeyProtector(char[] password)
131 throws NoSuchAlgorithmException
132 {
133 int i, j;
134
135 if (password == null) {
136 throw new IllegalArgumentException("password can't be null");
137 }
138 md = MessageDigest.getInstance(DIGEST_ALG);
139 // Convert password to byte array, so that it can be digested
140 passwdBytes = new byte[password.length * 2];
141 for (i=0, j=0; i<password.length; i++) {
142 passwdBytes[j++] = (byte)(password[i] >> 8);
143 passwdBytes[j++] = (byte)password[i];
144 }
145 // Use the cleaner to zero the password when no longer referenced
146 final byte[] k = this.passwdBytes;
147 CleanerFactory.cleaner().register(this,
148 () -> java.util.Arrays.fill(k, (byte)0x00));
149 }
150
151 /*
152 * Protects the given plaintext key, using the password provided at
153 * construction time.
154 */
155 public byte[] protect(Key key) throws KeyStoreException
156 {
157 int i;
158 int numRounds;
159 byte[] digest;
160 int xorOffset; // offset in xorKey where next digest will be stored
161 int encrKeyOffset = 0;
162
163 if (key == null) {
164 throw new IllegalArgumentException("plaintext key can't be null");
165 }
166
167 if (!"PKCS#8".equalsIgnoreCase(key.getFormat())) {
168 throw new KeyStoreException(
| 1 /*
2 * Copyright (c) 1997, 2018, 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.provider;
27
28 import java.io.IOException;
29 import java.io.UnsupportedEncodingException;
30 import java.security.Key;
31 import java.security.KeyStoreException;
32 import java.security.MessageDigest;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.SecureRandom;
35 import java.security.UnrecoverableKeyException;
36 import java.util.*;
37
38 import sun.security.pkcs.PKCS8Key;
39 import sun.security.pkcs.EncryptedPrivateKeyInfo;
40 import sun.security.x509.AlgorithmId;
41 import sun.security.util.ObjectIdentifier;
42 import sun.security.util.DerValue;
43
44 /**
45 * This is an implementation of a Sun proprietary, exportable algorithm
46 * intended for use when protecting (or recovering the cleartext version of)
47 * sensitive keys.
48 * This algorithm is not intended as a general purpose cipher.
49 *
50 * This is how the algorithm works for key protection:
51 *
52 * p - user password
53 * s - random salt
54 * X - xor key
55 * P - to-be-protected key
56 * Y - protected key
57 * R - what gets stored in the keystore
102
103 final class KeyProtector {
104
105 private static final int SALT_LEN = 20; // the salt length
106 private static final String DIGEST_ALG = "SHA";
107 private static final int DIGEST_LEN = 20;
108
109 // defined by JavaSoft
110 private static final String KEY_PROTECTOR_OID = "1.3.6.1.4.1.42.2.17.1.1";
111
112 // The password used for protecting/recovering keys passed through this
113 // key protector. We store it as a byte array, so that we can digest it.
114 private byte[] passwdBytes;
115
116 private MessageDigest md;
117
118
119 /**
120 * Creates an instance of this class, and initializes it with the given
121 * password.
122 */
123 public KeyProtector(byte[] passwordBytes)
124 throws NoSuchAlgorithmException
125 {
126 if (passwordBytes == null) {
127 throw new IllegalArgumentException("password can't be null");
128 }
129 md = MessageDigest.getInstance(DIGEST_ALG);
130 this.passwdBytes = passwordBytes;
131 }
132
133 /*
134 * Protects the given plaintext key, using the password provided at
135 * construction time.
136 */
137 public byte[] protect(Key key) throws KeyStoreException
138 {
139 int i;
140 int numRounds;
141 byte[] digest;
142 int xorOffset; // offset in xorKey where next digest will be stored
143 int encrKeyOffset = 0;
144
145 if (key == null) {
146 throw new IllegalArgumentException("plaintext key can't be null");
147 }
148
149 if (!"PKCS#8".equalsIgnoreCase(key.getFormat())) {
150 throw new KeyStoreException(
|