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.length() == 0) {
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 private char[] xor(char[] chars) {
75 if (chars != null) {
76 int mask = System.identityHashCode(this);
77 for (int i = 0; i < chars.length; i++) {
78 int key = KEYS[(i >> 1) % KEYS.length].hashCode();
79 key ^= mask;
80 chars[i] ^= ((i & 1) == 0) ? (key & 0xFFFF) : (key >>> 16);
81 }
82 }
83 return chars;
84 }
85
86 private static void clear(char[] chars) {
87 if (chars != null) {
88 for (int i = 0; i < chars.length; i++) {
89 chars[i] = '\0';
90 }
91 }
92 }
93
94 public void fill(AuthenticationContext context, String key, Map<String, String> data) {
95 requireNonNull(context, "context cannot be null");
96 char[] secret = copy(value);
97 xor(secret);
98 context.put(this.key, secret);
99
100 }
101
102 public void digest(AuthenticationDigest digest) {
103 char[] secret = copy(value);
104 try {
105 xor(secret);
106 digest.update(key);
107 digest.update(secret);
108 } finally {
109 clear(secret);
110 }
111 }
112
113 @Override
114 public boolean equals(Object obj) {
115 if (this == obj) {
116 return true;
117 }
118 if (obj == null || !getClass().equals(obj.getClass())) {
119 return false;
120 }
121 SecretAuthentication that = (SecretAuthentication) obj;
122 if (!Objects.equals(key, that.key) || secretHash != that.secretHash) {
123 return false;
124 }
125 char[] secret = copy(value);
126 char[] thatSecret = copy(that.value);
127 try {
128 xor(secret);
129 that.xor(thatSecret);
130 return Arrays.equals(secret, thatSecret);
131 } finally {
132 clear(secret);
133 clear(thatSecret);
134 }
135 }
136
137 @Override
138 public int hashCode() {
139 int hash = 17;
140 hash = hash * 31 + key.hashCode();
141 hash = hash * 31 + secretHash;
142 return hash;
143 }
144
145 @Override
146 public String toString() {
147 return key + "=" + ((value != null) ? "***" : "null");
148 }
149 }