1 package org
.argeo
.osgi
.useradmin
;
3 import java
.math
.BigInteger
;
4 import java
.nio
.ByteBuffer
;
5 import java
.nio
.CharBuffer
;
6 import java
.nio
.charset
.StandardCharsets
;
7 import java
.security
.MessageDigest
;
8 import java
.security
.NoSuchAlgorithmException
;
9 import java
.security
.spec
.InvalidKeySpecException
;
10 import java
.security
.spec
.KeySpec
;
11 import java
.util
.Arrays
;
13 import javax
.crypto
.SecretKeyFactory
;
14 import javax
.crypto
.spec
.PBEKeySpec
;
16 /** Utilities around digests, mostly those related to passwords. */
18 final static String PASSWORD_SCHEME_SHA
= "SHA";
19 final static String PASSWORD_SCHEME_PBKDF2_SHA256
= "PBKDF2_SHA256";
21 static byte[] sha1(byte[] bytes
) {
23 MessageDigest digest
= MessageDigest
.getInstance("SHA1");
25 byte[] checksum
= digest
.digest();
27 } catch (NoSuchAlgorithmException e
) {
28 throw new IllegalStateException("Cannot SHA1 digest", e
);
32 static byte[] toPasswordScheme(String passwordScheme
, char[] password
, byte[] salt
, Integer iterations
,
35 if (PASSWORD_SCHEME_SHA
.equals(passwordScheme
)) {
36 MessageDigest digest
= MessageDigest
.getInstance("SHA1");
37 byte[] bytes
= charsToBytes(password
);
39 return digest
.digest();
40 } else if (PASSWORD_SCHEME_PBKDF2_SHA256
.equals(passwordScheme
)) {
41 KeySpec spec
= new PBEKeySpec(password
, salt
, iterations
, keyLength
);
43 SecretKeyFactory f
= SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA256");
44 final int ITERATION_LENGTH
= 4;
45 byte[] key
= f
.generateSecret(spec
).getEncoded();
46 byte[] result
= new byte[ITERATION_LENGTH
+ salt
.length
+ key
.length
];
47 byte iterationsArr
[] = new BigInteger(iterations
.toString()).toByteArray();
48 if (iterationsArr
.length
< ITERATION_LENGTH
) {
49 Arrays
.fill(result
, 0, ITERATION_LENGTH
- iterationsArr
.length
, (byte) 0);
50 System
.arraycopy(iterationsArr
, 0, result
, ITERATION_LENGTH
- iterationsArr
.length
,
51 iterationsArr
.length
);
53 System
.arraycopy(iterationsArr
, 0, result
, 0, ITERATION_LENGTH
);
55 System
.arraycopy(salt
, 0, result
, ITERATION_LENGTH
, salt
.length
);
56 System
.arraycopy(key
, 0, result
, ITERATION_LENGTH
+ salt
.length
, key
.length
);
59 throw new UnsupportedOperationException("Unkown password scheme " + passwordScheme
);
61 } catch (NoSuchAlgorithmException
| InvalidKeySpecException e
) {
62 throw new IllegalStateException("Cannot digest", e
);
66 static char[] bytesToChars(Object obj
) {
67 if (obj
instanceof char[])
69 if (!(obj
instanceof byte[]))
70 throw new IllegalArgumentException(obj
.getClass() + " is not a byte array");
71 ByteBuffer fromBuffer
= ByteBuffer
.wrap((byte[]) obj
);
72 CharBuffer toBuffer
= StandardCharsets
.UTF_8
.decode(fromBuffer
);
73 char[] res
= Arrays
.copyOfRange(toBuffer
.array(), toBuffer
.position(), toBuffer
.limit());
74 // Arrays.fill(fromBuffer.array(), (byte) 0); // clear sensitive data
75 // Arrays.fill((byte[]) obj, (byte) 0); // clear sensitive data
76 // Arrays.fill(toBuffer.array(), '\u0000'); // clear sensitive data
80 static byte[] charsToBytes(char[] chars
) {
81 CharBuffer charBuffer
= CharBuffer
.wrap(chars
);
82 ByteBuffer byteBuffer
= StandardCharsets
.UTF_8
.encode(charBuffer
);
83 byte[] bytes
= Arrays
.copyOfRange(byteBuffer
.array(), byteBuffer
.position(), byteBuffer
.limit());
84 // Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
85 // Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
89 static String
sha1str(String str
) {
90 byte[] hash
= sha1(str
.getBytes(StandardCharsets
.UTF_8
));
91 return encodeHexString(hash
);
94 final private static char[] hexArray
= "0123456789abcdef".toCharArray();
98 * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
99 * -a-hex-string-in-java
101 public static String
encodeHexString(byte[] bytes
) {
102 char[] hexChars
= new char[bytes
.length
* 2];
103 for (int j
= 0; j
< bytes
.length
; j
++) {
104 int v
= bytes
[j
] & 0xFF;
105 hexChars
[j
* 2] = hexArray
[v
>>> 4];
106 hexChars
[j
* 2 + 1] = hexArray
[v
& 0x0F];
108 return new String(hexChars
);
111 private DigestUtils() {