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
.spec
.KeySpec
;
9 import java
.util
.Arrays
;
11 import javax
.crypto
.SecretKeyFactory
;
12 import javax
.crypto
.spec
.PBEKeySpec
;
14 /** Utilities around digests, mostly those related to passwords. */
16 final static String PASSWORD_SCHEME_SHA
= "SHA";
17 final static String PASSWORD_SCHEME_PBKDF2_SHA256
= "PBKDF2_SHA256";
19 static byte[] sha1(byte[] bytes
) {
21 MessageDigest digest
= MessageDigest
.getInstance("SHA1");
23 byte[] checksum
= digest
.digest();
25 } catch (Exception e
) {
26 throw new UserDirectoryException("Cannot SHA1 digest", e
);
30 static byte[] toPasswordScheme(String passwordScheme
, char[] password
, byte[] salt
, Integer iterations
,
33 if (PASSWORD_SCHEME_SHA
.equals(passwordScheme
)) {
34 MessageDigest digest
= MessageDigest
.getInstance("SHA1");
35 byte[] bytes
= charsToBytes(password
);
37 return digest
.digest();
38 } else if (PASSWORD_SCHEME_PBKDF2_SHA256
.equals(passwordScheme
)) {
39 KeySpec spec
= new PBEKeySpec(password
, salt
, iterations
, keyLength
);
41 SecretKeyFactory f
= SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA256");
42 final int ITERATION_LENGTH
= 4;
43 byte[] key
= f
.generateSecret(spec
).getEncoded();
44 byte[] result
= new byte[ITERATION_LENGTH
+ salt
.length
+ key
.length
];
45 byte iterationsArr
[] = new BigInteger(iterations
.toString()).toByteArray();
46 if (iterationsArr
.length
< ITERATION_LENGTH
) {
47 Arrays
.fill(result
, 0, ITERATION_LENGTH
- iterationsArr
.length
, (byte) 0);
48 System
.arraycopy(iterationsArr
, 0, result
, ITERATION_LENGTH
- iterationsArr
.length
,
49 iterationsArr
.length
);
51 System
.arraycopy(iterationsArr
, 0, result
, 0, ITERATION_LENGTH
);
53 System
.arraycopy(salt
, 0, result
, ITERATION_LENGTH
, salt
.length
);
54 System
.arraycopy(key
, 0, result
, ITERATION_LENGTH
+ salt
.length
, key
.length
);
57 throw new UnsupportedOperationException("Unkown password scheme " + passwordScheme
);
59 } catch (Exception e
) {
60 throw new UserDirectoryException("Cannot digest", e
);
64 static char[] bytesToChars(Object obj
) {
65 if (obj
instanceof char[])
67 if (!(obj
instanceof byte[]))
68 throw new IllegalArgumentException(obj
.getClass() + " is not a byte array");
69 ByteBuffer fromBuffer
= ByteBuffer
.wrap((byte[]) obj
);
70 CharBuffer toBuffer
= StandardCharsets
.UTF_8
.decode(fromBuffer
);
71 char[] res
= Arrays
.copyOfRange(toBuffer
.array(), toBuffer
.position(), toBuffer
.limit());
72 // Arrays.fill(fromBuffer.array(), (byte) 0); // clear sensitive data
73 // Arrays.fill((byte[]) obj, (byte) 0); // clear sensitive data
74 // Arrays.fill(toBuffer.array(), '\u0000'); // clear sensitive data
78 static byte[] charsToBytes(char[] chars
) {
79 CharBuffer charBuffer
= CharBuffer
.wrap(chars
);
80 ByteBuffer byteBuffer
= StandardCharsets
.UTF_8
.encode(charBuffer
);
81 byte[] bytes
= Arrays
.copyOfRange(byteBuffer
.array(), byteBuffer
.position(), byteBuffer
.limit());
82 // Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
83 // Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
87 static String
sha1str(String str
) {
88 byte[] hash
= sha1(str
.getBytes(StandardCharsets
.UTF_8
));
89 return encodeHexString(hash
);
92 final private static char[] hexArray
= "0123456789abcdef".toCharArray();
96 * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
97 * -a-hex-string-in-java
99 public static String
encodeHexString(byte[] bytes
) {
100 char[] hexChars
= new char[bytes
.length
* 2];
101 for (int j
= 0; j
< bytes
.length
; j
++) {
102 int v
= bytes
[j
] & 0xFF;
103 hexChars
[j
* 2] = hexArray
[v
>>> 4];
104 hexChars
[j
* 2 + 1] = hexArray
[v
& 0x0F];
106 return new String(hexChars
);
109 private DigestUtils() {