Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
41154 views
1
/*
2
* Copyright (c) 2003, 2013, 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.pkcs11;
27
28
import java.io.*;
29
import java.security.*;
30
import sun.security.pkcs11.wrapper.*;
31
32
/**
33
* SecureRandom implementation class. Some tokens support only
34
* C_GenerateRandom() and not C_SeedRandom(). In order not to lose an
35
* application specified seed, we create a SHA1PRNG that we mix with in that
36
* case.
37
*
38
* Note that since SecureRandom is thread safe, we only need one
39
* instance per PKCS#11 token instance. It is created on demand and cached
40
* in the SunPKCS11 class.
41
*
42
* Also note that we obtain the PKCS#11 session on demand, no need to tie one
43
* up.
44
*
45
* @author Andreas Sterbenz
46
* @since 1.5
47
*/
48
final class P11SecureRandom extends SecureRandomSpi {
49
50
private static final long serialVersionUID = -8939510236124553291L;
51
52
// token instance
53
private final Token token;
54
55
// PRNG for mixing, non-null if active (i.e. setSeed() has been called)
56
private volatile SecureRandom mixRandom;
57
58
// buffer, if mixing is used
59
private byte[] mixBuffer;
60
61
// bytes remaining in mixBuffer, if mixing is used
62
private int buffered;
63
64
/*
65
* we buffer data internally for efficiency but limit the lifetime
66
* to avoid using stale bits.
67
*/
68
// lifetime in ms, currently 100 ms (0.1 s)
69
private static final long MAX_IBUFFER_TIME = 100;
70
71
// size of the internal buffer
72
private static final int IBUFFER_SIZE = 32;
73
74
// internal buffer for the random bits
75
private transient byte[] iBuffer = new byte[IBUFFER_SIZE];
76
77
// number of bytes remain in iBuffer
78
private transient int ibuffered = 0;
79
80
// time that data was read into iBuffer
81
private transient long lastRead = 0L;
82
83
P11SecureRandom(Token token) {
84
this.token = token;
85
}
86
87
// see JCA spec
88
@Override
89
protected synchronized void engineSetSeed(byte[] seed) {
90
if (seed == null) {
91
throw new NullPointerException("seed must not be null");
92
}
93
Session session = null;
94
try {
95
session = token.getOpSession();
96
token.p11.C_SeedRandom(session.id(), seed);
97
} catch (PKCS11Exception e) {
98
// cannot set seed
99
// let a SHA1PRNG use that seed instead
100
SecureRandom random = mixRandom;
101
if (random != null) {
102
random.setSeed(seed);
103
} else {
104
try {
105
mixBuffer = new byte[20];
106
random = SecureRandom.getInstance("SHA1PRNG");
107
// initialize object before assigning to class field
108
random.setSeed(seed);
109
mixRandom = random;
110
} catch (NoSuchAlgorithmException ee) {
111
throw new ProviderException(ee);
112
}
113
}
114
} finally {
115
token.releaseSession(session);
116
}
117
}
118
119
// see JCA spec
120
@Override
121
protected void engineNextBytes(byte[] bytes) {
122
if ((bytes == null) || (bytes.length == 0)) {
123
return;
124
}
125
if (bytes.length <= IBUFFER_SIZE) {
126
int ofs = 0;
127
synchronized (iBuffer) {
128
while (ofs < bytes.length) {
129
long time = System.currentTimeMillis();
130
// refill the internal buffer if empty or stale
131
if ((ibuffered == 0) ||
132
!(time - lastRead < MAX_IBUFFER_TIME)) {
133
lastRead = time;
134
implNextBytes(iBuffer);
135
ibuffered = IBUFFER_SIZE;
136
}
137
// copy the buffered bytes into 'bytes'
138
while ((ofs < bytes.length) && (ibuffered > 0)) {
139
bytes[ofs++] = iBuffer[IBUFFER_SIZE - ibuffered--];
140
}
141
}
142
}
143
} else {
144
// avoid using the buffer - just fill bytes directly
145
implNextBytes(bytes);
146
}
147
148
}
149
150
// see JCA spec
151
@Override
152
protected byte[] engineGenerateSeed(int numBytes) {
153
byte[] b = new byte[numBytes];
154
engineNextBytes(b);
155
return b;
156
}
157
158
private void mix(byte[] b) {
159
SecureRandom random = mixRandom;
160
if (random == null) {
161
// avoid mixing if setSeed() has never been called
162
return;
163
}
164
synchronized (this) {
165
int ofs = 0;
166
int len = b.length;
167
while (len-- > 0) {
168
if (buffered == 0) {
169
random.nextBytes(mixBuffer);
170
buffered = mixBuffer.length;
171
}
172
b[ofs++] ^= mixBuffer[mixBuffer.length - buffered];
173
buffered--;
174
}
175
}
176
}
177
178
// fill up the specified buffer with random bytes, and mix them
179
private void implNextBytes(byte[] bytes) {
180
Session session = null;
181
try {
182
session = token.getOpSession();
183
token.p11.C_GenerateRandom(session.id(), bytes);
184
mix(bytes);
185
} catch (PKCS11Exception e) {
186
throw new ProviderException("nextBytes() failed", e);
187
} finally {
188
token.releaseSession(session);
189
}
190
}
191
192
private void readObject(ObjectInputStream in)
193
throws IOException, ClassNotFoundException {
194
in.defaultReadObject();
195
// assign default values to non-null transient fields
196
iBuffer = new byte[IBUFFER_SIZE];
197
ibuffered = 0;
198
lastRead = 0L;
199
}
200
}
201
202