blob: de830226be8741c9c66a29d5a29998c2516ab0b7 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003 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
26package sun.security.pkcs11;
27
28import java.util.*;
29
30import java.security.*;
31
32import sun.security.pkcs11.wrapper.*;
33import sun.security.pkcs11.wrapper.PKCS11Constants.*;
34
35/**
36 * SecureRandom implementation class. Some tokens support only
37 * C_GenerateRandom() and not C_SeedRandom(). In order not to lose an
38 * application specified seed, we create a SHA1PRNG that we mix with in that
39 * case.
40 *
41 * Note that since SecureRandom is thread safe, we only need one
42 * instance per PKCS#11 token instance. It is created on demand and cached
43 * in the SunPKCS11 class.
44 *
45 * Also note that we obtain the PKCS#11 session on demand, no need to tie one
46 * up.
47 *
48 * @author Andreas Sterbenz
49 * @since 1.5
50 */
51final class P11SecureRandom extends SecureRandomSpi {
52
53 private static final long serialVersionUID = -8939510236124553291L;
54
55 // token instance
56 private final Token token;
57
58 // PRNG for mixing, non-null if active (i.e. setSeed() has been called)
59 private volatile SecureRandom mixRandom;
60
61 // buffer, if mixing is used
62 private byte[] mixBuffer;
63
64 // bytes remaining in buffer, if mixing is used
65 private int buffered;
66
67 P11SecureRandom(Token token) {
68 this.token = token;
69 }
70
71 // see JCA spec
72 protected synchronized void engineSetSeed(byte[] seed) {
73 if (seed == null) {
74 throw new NullPointerException("seed must not be null");
75 }
76 Session session = null;
77 try {
78 session = token.getOpSession();
79 token.p11.C_SeedRandom(session.id(), seed);
80 } catch (PKCS11Exception e) {
81 // cannot set seed
82 // let a SHA1PRNG use that seed instead
83 SecureRandom random = mixRandom;
84 if (random != null) {
85 random.setSeed(seed);
86 } else {
87 try {
88 mixBuffer = new byte[20];
89 random = SecureRandom.getInstance("SHA1PRNG");
90 // initialize object before assigning to class field
91 random.setSeed(seed);
92 mixRandom = random;
93 } catch (NoSuchAlgorithmException ee) {
94 throw new ProviderException(ee);
95 }
96 }
97 } finally {
98 token.releaseSession(session);
99 }
100 }
101
102 // see JCA spec
103 protected void engineNextBytes(byte[] bytes) {
104 if ((bytes == null) || (bytes.length == 0)) {
105 return;
106 }
107 Session session = null;
108 try {
109 session = token.getOpSession();
110 token.p11.C_GenerateRandom(session.id(), bytes);
111 mix(bytes);
112 } catch (PKCS11Exception e) {
113 throw new ProviderException("nextBytes() failed", e);
114 } finally {
115 token.releaseSession(session);
116 }
117 }
118
119 // see JCA spec
120 protected byte[] engineGenerateSeed(int numBytes) {
121 byte[] b = new byte[numBytes];
122 engineNextBytes(b);
123 return b;
124 }
125
126 private void mix(byte[] b) {
127 SecureRandom random = mixRandom;
128 if (random == null) {
129 // avoid mixing if setSeed() has never been called
130 return;
131 }
132 synchronized (this) {
133 int ofs = 0;
134 int len = b.length;
135 while (len-- > 0) {
136 if (buffered == 0) {
137 random.nextBytes(mixBuffer);
138 buffered = mixBuffer.length;
139 }
140 b[ofs++] ^= mixBuffer[mixBuffer.length - buffered];
141 buffered--;
142 }
143 }
144 }
145
146}