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