91 } else { |
91 } else { |
92 this.passwd = passwd.clone(); |
92 this.passwd = passwd.clone(); |
93 } |
93 } |
94 // Convert the password from char[] to byte[] |
94 // Convert the password from char[] to byte[] |
95 byte[] passwdBytes = getPasswordBytes(this.passwd); |
95 byte[] passwdBytes = getPasswordBytes(this.passwd); |
96 |
96 // remove local copy |
97 this.salt = keySpec.getSalt(); |
97 if (passwd != null) Arrays.fill(passwd, '\0'); |
98 if (salt == null) { |
98 |
99 throw new InvalidKeySpecException("Salt not found"); |
|
100 } |
|
101 this.iterCount = keySpec.getIterationCount(); |
|
102 if (iterCount == 0) { |
|
103 throw new InvalidKeySpecException("Iteration count not found"); |
|
104 } else if (iterCount < 0) { |
|
105 throw new InvalidKeySpecException("Iteration count is negative"); |
|
106 } |
|
107 int keyLength = keySpec.getKeyLength(); |
|
108 if (keyLength == 0) { |
|
109 throw new InvalidKeySpecException("Key length not found"); |
|
110 } else if (keyLength < 0) { |
|
111 throw new InvalidKeySpecException("Key length is negative"); |
|
112 } |
|
113 try { |
99 try { |
|
100 this.salt = keySpec.getSalt(); |
|
101 if (salt == null) { |
|
102 throw new InvalidKeySpecException("Salt not found"); |
|
103 } |
|
104 this.iterCount = keySpec.getIterationCount(); |
|
105 if (iterCount == 0) { |
|
106 throw new InvalidKeySpecException("Iteration count not found"); |
|
107 } else if (iterCount < 0) { |
|
108 throw new InvalidKeySpecException("Iteration count is negative"); |
|
109 } |
|
110 int keyLength = keySpec.getKeyLength(); |
|
111 if (keyLength == 0) { |
|
112 throw new InvalidKeySpecException("Key length not found"); |
|
113 } else if (keyLength < 0) { |
|
114 throw new InvalidKeySpecException("Key length is negative"); |
|
115 } |
114 this.prf = Mac.getInstance(prfAlgo); |
116 this.prf = Mac.getInstance(prfAlgo); |
115 // SunPKCS11 requires a non-empty PBE password |
117 // SunPKCS11 requires a non-empty PBE password |
116 if (passwdBytes.length == 0 && |
118 if (passwdBytes.length == 0 && |
117 this.prf.getProvider().getName().startsWith("SunPKCS11")) { |
119 this.prf.getProvider().getName().startsWith("SunPKCS11")) { |
118 this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance()); |
120 this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance()); |
119 } |
121 } |
|
122 this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength); |
120 } catch (NoSuchAlgorithmException nsae) { |
123 } catch (NoSuchAlgorithmException nsae) { |
121 // not gonna happen; re-throw just in case |
124 // not gonna happen; re-throw just in case |
122 InvalidKeySpecException ike = new InvalidKeySpecException(); |
125 InvalidKeySpecException ike = new InvalidKeySpecException(); |
123 ike.initCause(nsae); |
126 ike.initCause(nsae); |
124 throw ike; |
127 throw ike; |
125 } |
128 } finally { |
126 this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength); |
129 Arrays.fill(passwdBytes, (byte) 0x00); |
127 |
130 |
128 // Use the cleaner to zero the key when no longer referenced |
131 // Use the cleaner to zero the key when no longer referenced |
129 final byte[] k = this.key; |
132 final byte[] k = this.key; |
130 final char[] p = this.passwd; |
133 final char[] p = this.passwd; |
131 CleanerFactory.cleaner().register(this, |
134 CleanerFactory.cleaner().register(this, |
132 () -> { |
135 () -> { |
133 java.util.Arrays.fill(k, (byte)0x00); |
136 Arrays.fill(k, (byte) 0x00); |
134 java.util.Arrays.fill(p, '0'); |
137 Arrays.fill(p, '\0'); |
135 }); |
138 }); |
|
139 } |
136 } |
140 } |
137 |
141 |
138 private static byte[] deriveKey(final Mac prf, final byte[] password, |
142 private static byte[] deriveKey(final Mac prf, final byte[] password, |
139 byte[] salt, int iterCount, int keyLengthInBit) { |
143 byte[] salt, int iterCount, int keyLengthInBit) { |
140 int keyLength = keyLengthInBit/8; |
144 int keyLength = keyLengthInBit/8; |