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