File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\jenkins\security\HMACConfidentialKey.java.html

1 package jenkins.security;
2
3 import hudson.Util;
4
5 import javax.crypto.KeyGenerator;
6 import javax.crypto.Mac;
7 import javax.crypto.SecretKey;
8 import javax.crypto.spec.SecretKeySpec;
9 import java.io.IOException;
10 import java.io.UnsupportedEncodingException;
11 import java.security.GeneralSecurityException;
12 import java.security.NoSuchAlgorithmException;
13 import java.util.Arrays;
14
15 /**
16 * {@link ConfidentialKey} that's used for creating a token by hashing some information with secret
17 * (such as <tt>hash(msg|secret)</tt>).
18 *
19 * <p>
20 * This provides more secure version of it by using HMAC.
21 * See http://rdist.root.org/2009/10/29/stop-using-unsafe-keyed-hashes-use-hmac/ for background.
22 * This implementation also never leaks the secret value to outside, so it makes it impossible
23 * for the careless caller to misuse the key (thus protecting ourselves from our own stupidity!)
24 *
25 * @author Kohsuke Kawaguchi
26 * @since 1.498
27 */
28 public class HMACConfidentialKey extends ConfidentialKey {
29 private volatile SecretKey key;
30 private final int length;
31
32 /**
33 * @param length
34 * Byte length of the HMAC code.
35 * By default we use HMAC-SHA256, which produces 256bit (=32bytes) HMAC,
36 * but if different use cases requires a shorter HMAC, specify the desired length here.
37 * Note that when using {@link #mac(String)}, string encoding causes the length to double.
38 * So if you want to get 16-letter HMAC, you specify 8 here.
39 */
40 public HMACConfidentialKey(String id, int length) {
41 super(id);
42 this.length = length;
43 }
44
45 /**
46 * Calls into {@link #HMACConfidentialKey(String, int)} with the longest possible HMAC length.
47 */
48 public HMACConfidentialKey(String id) {
49 this(id,Integer.MAX_VALUE);
50 }
51
52 /**
53 * Calls into {@link #HMACConfidentialKey(String, int)} by combining the class name and the shortName
54 * as the ID.
55 */
56 public HMACConfidentialKey(Class owner, String shortName, int length) {
57 this(owner.getName()+'.'+shortName,length);
58 }
59
60 public HMACConfidentialKey(Class owner, String shortName) {
61 this(owner,shortName,Integer.MAX_VALUE);
62 }
63
64
65 /**
66 * Computes the message authentication code for the specified byte sequence.
67 */
68 public byte[] mac(byte[] message) {
69 return chop(createMac().doFinal(message));
70 }
71
72 /**
73 * Convenience method for verifying the MAC code.
74 */
75 public boolean checkMac(byte[] message, byte[] mac) {
76 return Arrays.equals(mac(message),mac);
77 }
78
79 /**
80 * Computes the message authentication code and return it as a string.
81 * While redundant, often convenient.
82 */
83 public String mac(String message) {
84 try {
85 return Util.toHexString(mac(message.getBytes("UTF-8")));
86 } catch (UnsupportedEncodingException e) {
87 throw new AssertionError(e);
88 }
89 }
90
91 /**
92 * Verifies MAC constructed from {@link #mac(String)}
93 */
94 public boolean checkMac(String message, String mac) {
95 return mac(message).equals(mac);
96 }
97
98 private byte[] chop(byte[] mac) {
99 if (mac.length<=length) return mac; // already too short
100
101 byte[] b = new byte[length];
102 System.arraycopy(mac,0,b,0,b.length);
103 return b;
104 }
105
106 /**
107 * Creates a new {@link Mac} object.
108 */
109 public Mac createMac() {
110 try {
111 Mac mac = Mac.getInstance(ALGORITHM);
112 mac.init(getKey());
113 return mac;
114 } catch (GeneralSecurityException e) {
115 // Javadoc says HmacSHA256 must be supported by every Java implementation.
116 throw new Error(ALGORITHM+" not supported?",e);
117 }
118 }
119
120 private SecretKey getKey() {
121 if (key==null) {
122 synchronized (this) {
123 if (key==null) {
124 try {
125 byte[] encoded = load();
126 if (encoded==null) {
127 KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
128 SecretKey key = kg.generateKey();
129 store(encoded=key.getEncoded());
130 }
131 key = new SecretKeySpec(encoded,ALGORITHM);
132 } catch (IOException e) {
133 throw new Error("Failed to load the key: "+getId(),e);
134 } catch (NoSuchAlgorithmException e) {
135 throw new Error("Failed to load the key: "+getId(),e);
136 }
137 }
138 }
139 }
140 return key;
141 }
142
143 private static final String ALGORITHM = "HmacSHA256";
144 }
145