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 char[] secret = copy( value );
114 xor( secret );
115 context.put( this.key, secret );
116
117 }
118
119 public void digest( AuthenticationDigest digest )
120 {
121 char[] secret = copy( value );
122 try
123 {
124 xor( secret );
125 digest.update( key );
126 digest.update( secret );
127 }
128 finally
129 {
130 clear( secret );
131 }
132 }
133
134 @Override
135 public boolean equals( Object obj )
136 {
137 if ( this == obj )
138 {
139 return true;
140 }
141 if ( obj == null || !getClass().equals( obj.getClass() ) )
142 {
143 return false;
144 }
145 SecretAuthentication that = (SecretAuthentication) obj;
146 if ( !Objects.equals( key, that.key ) || secretHash != that.secretHash )
147 {
148 return false;
149 }
150 char[] secret = copy( value );
151 char[] thatSecret = copy( that.value );
152 try
153 {
154 xor( secret );
155 that.xor( thatSecret );
156 return Arrays.equals( secret, thatSecret );
157 }
158 finally
159 {
160 clear( secret );
161 clear( thatSecret );
162 }
163 }
164
165 @Override
166 public int hashCode()
167 {
168 int hash = 17;
169 hash = hash * 31 + key.hashCode();
170 hash = hash * 31 + secretHash;
171 return hash;
172 }
173
174 @Override
175 public String toString()
176 {
177 return key + "=" + ( ( value != null ) ? "***" : "null" );
178 }
179
180 }