1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.util.repository;
20
21 import java.util.Arrays;
22 import java.util.Map;
23 import java.util.Objects;
24
25 import org.eclipse.aether.repository.Authentication;
26 import org.eclipse.aether.repository.AuthenticationContext;
27 import org.eclipse.aether.repository.AuthenticationDigest;
28
29 import static java.util.Objects.requireNonNull;
30
31
32
33
34
35
36 final class SecretAuthentication implements Authentication {
37
38 private static final Object[] KEYS;
39
40 static {
41 KEYS = new Object[16];
42 for (int i = 0; i < KEYS.length; i++) {
43 KEYS[i] = new Object();
44 }
45 }
46
47 private final String key;
48
49 private final char[] value;
50
51 private final int secretHash;
52
53 SecretAuthentication(String key, String value) {
54 this((value != null) ? value.toCharArray() : null, key);
55 }
56
57 SecretAuthentication(String key, char[] value) {
58 this(copy(value), key);
59 }
60
61 private SecretAuthentication(char[] value, String key) {
62 this.key = requireNonNull(key, "authentication key cannot be null");
63 if (key.isEmpty()) {
64 throw new IllegalArgumentException("authentication key cannot be empty");
65 }
66 this.secretHash = Arrays.hashCode(value) ^ KEYS[0].hashCode();
67 this.value = xor(value);
68 }
69
70 private static char[] copy(char[] chars) {
71 return (chars != null) ? chars.clone() : null;
72 }
73
74 @SuppressWarnings("checkstyle:magicnumber")
75 private char[] xor(char[] chars) {
76 if (chars != null) {
77 int mask = System.identityHashCode(this);
78 for (int i = 0; i < chars.length; i++) {
79 int key = KEYS[(i >> 1) % KEYS.length].hashCode();
80 key ^= mask;
81 chars[i] ^= ((i & 1) == 0) ? (key & 0xFFFF) : (key >>> 16);
82 }
83 }
84 return chars;
85 }
86
87 private static void clear(char[] chars) {
88 if (chars != null) {
89 for (int i = 0; i < chars.length; i++) {
90 chars[i] = '\0';
91 }
92 }
93 }
94
95 public void fill(AuthenticationContext context, String key, Map<String, String> data) {
96 requireNonNull(context, "context cannot be null");
97 char[] secret = copy(value);
98 xor(secret);
99 context.put(this.key, secret);
100
101 }
102
103 public void digest(AuthenticationDigest digest) {
104 char[] secret = copy(value);
105 try {
106 xor(secret);
107 digest.update(key);
108 digest.update(secret);
109 } finally {
110 clear(secret);
111 }
112 }
113
114 @Override
115 public boolean equals(Object obj) {
116 if (this == obj) {
117 return true;
118 }
119 if (obj == null || !getClass().equals(obj.getClass())) {
120 return false;
121 }
122 SecretAuthentication that = (SecretAuthentication) obj;
123 if (!Objects.equals(key, that.key) || secretHash != that.secretHash) {
124 return false;
125 }
126 char[] secret = copy(value);
127 char[] thatSecret = copy(that.value);
128 try {
129 xor(secret);
130 that.xor(thatSecret);
131 return Arrays.equals(secret, thatSecret);
132 } finally {
133 clear(secret);
134 clear(thatSecret);
135 }
136 }
137
138 @Override
139 public int hashCode() {
140 int hash = 17;
141 hash = hash * 31 + key.hashCode();
142 hash = hash * 31 + secretHash;
143 return hash;
144 }
145
146 @Override
147 public String toString() {
148 return key + "=" + ((value != null) ? "***" : "null");
149 }
150 }