1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.ldap.client.template;
21
22
23 import java.nio.ByteBuffer;
24 import java.nio.CharBuffer;
25 import java.nio.charset.Charset;
26 import java.util.Arrays;
27
28
29
30
31
32
33
34
35
36
37 public final class MemoryClearingBuffer
38 {
39 private static final Charset UTF8 = Charset.forName( "UTF-8" );
40 private byte[] computedBytes;
41 private char[] computedChars;
42 private byte[] originalBytes;
43 private char[] originalChars;
44 private char[] precomputedChars;
45
46
47 private MemoryClearingBuffer( byte[] originalBytes, char[] originalChars, boolean trim, boolean lowerCase )
48 {
49 this.originalBytes = originalBytes;
50 this.originalChars = originalChars;
51
52 if ( trim || lowerCase )
53 {
54 if ( this.originalChars == null )
55 {
56 throw new UnsupportedOperationException( "trim and lowerCase only applicable to char[]" );
57 }
58
59 char[] working = Arrays.copyOf( originalChars, originalChars.length );
60 int startIndex = 0;
61 int endIndex = working.length;
62
63 if ( trim )
64 {
65
66 for ( ; startIndex < working.length; startIndex++ )
67 {
68 if ( !Character.isWhitespace( working[startIndex] ) )
69 {
70 break;
71 }
72 }
73
74
75 for ( endIndex--; endIndex > startIndex; endIndex-- )
76 {
77 if ( !Character.isWhitespace( working[endIndex] ) )
78 {
79 break;
80 }
81 }
82 endIndex++;
83 }
84
85 if ( lowerCase )
86 {
87
88 for ( int i = startIndex; i < endIndex; i++ )
89 {
90 working[i] = Character.toLowerCase( working[i] );
91 }
92 }
93
94 this.precomputedChars = new char[endIndex - startIndex];
95 System.arraycopy( working, startIndex, this.precomputedChars, 0, endIndex - startIndex );
96 }
97 else
98 {
99 this.precomputedChars = this.originalChars;
100 }
101 }
102
103
104
105
106
107
108
109
110
111 public static MemoryClearingBuffer newInstance( byte[] bytes )
112 {
113 return new MemoryClearingBuffer( bytes, null, false, false );
114 }
115
116
117
118
119
120
121
122
123
124 public static MemoryClearingBuffer newInstance( char[] chars )
125 {
126 return new MemoryClearingBuffer( null, chars, false, false );
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public static MemoryClearingBuffer newInstance( char[] chars, boolean trim, boolean lowerCase )
142 {
143 return new MemoryClearingBuffer( null, chars, trim, lowerCase );
144 }
145
146
147
148
149
150 public void clear()
151 {
152
153 if ( computedBytes != null )
154 {
155 Arrays.fill( computedBytes, ( byte ) 0 );
156 }
157 if ( computedChars != null )
158 {
159 Arrays.fill( computedChars, '0' );
160 }
161 if ( precomputedChars != null && precomputedChars != this.originalChars )
162 {
163
164 Arrays.fill( precomputedChars, '0' );
165 }
166
167 computedBytes = null;
168 computedChars = null;
169 originalBytes = null;
170 originalChars = null;
171 precomputedChars = null;
172 }
173
174
175
176
177
178
179
180
181 byte[] getComputedBytes()
182 {
183 if ( computedBytes == null )
184 {
185 ByteBuffer byteBuffer = UTF8.encode(
186 CharBuffer.wrap( precomputedChars, 0, precomputedChars.length ) );
187 computedBytes = new byte[byteBuffer.remaining()];
188 byteBuffer.get( computedBytes );
189
190
191 byteBuffer.flip();
192 byte[] nullifier = new byte[byteBuffer.limit()];
193 Arrays.fill( nullifier, ( byte ) 0 );
194 byteBuffer.put( nullifier );
195 }
196 return computedBytes;
197 }
198
199
200
201
202
203
204
205
206 private char[] getComputedChars()
207 {
208 if ( computedChars == null )
209 {
210 CharBuffer charBuffer = UTF8.decode(
211 ByteBuffer.wrap( originalBytes, 0, originalBytes.length ) );
212 computedChars = new char[charBuffer.remaining()];
213 charBuffer.get( computedChars );
214
215
216 charBuffer.flip();
217 char[] nullifier = new char[charBuffer.limit()];
218 Arrays.fill( nullifier, ( char ) 0 );
219 charBuffer.put( nullifier );
220 }
221 return computedChars;
222 }
223
224
225
226
227
228
229
230
231 public byte[] getBytes()
232 {
233 return originalBytes == null
234 ? getComputedBytes()
235 : originalBytes;
236 }
237
238
239
240
241
242
243
244 public char[] getChars()
245 {
246 return precomputedChars == null
247 ? getComputedChars()
248 : precomputedChars;
249 }
250 }