1 /**
2 * SecureQueue
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *     2012 Markus Wanner
8 *
9 * License:
10 * Botan is released under the Simplified BSD License (see LICENSE.md)
11 */
12 module botan.filters.secqueue;
13 
14 import botan.filters.data_src;
15 import botan.filters.filter;
16 import botan.utils.types;
17 import botan.utils.mem_ops;
18 import botan.constants;
19 import std.algorithm;
20 /**
21 * A queue that knows how to zeroise itself
22 */
23 final class SecureQueue : FanoutFilter, DataSourceImpl, Filterable
24 {
25 public:
26     override @property string name() const { return "Queue"; }
27 
28     /*
29     * Add some bytes to the queue
30     */
31     override void write(const(ubyte)* input, size_t length)
32     {
33         if (!m_head)
34             m_head = m_tail = new SecureQueueNode;
35         while (length)
36         {
37             const size_t n = m_tail.write(input, length);
38             input += n;
39             length -= n;
40             if (length)
41             {
42                 m_tail.m_next = new SecureQueueNode;
43                 m_tail = m_tail.m_next;
44             }
45         }
46     }
47 
48     /*
49     * Read some bytes from the queue
50     */
51     size_t read(ubyte* output, size_t length)
52     {
53         size_t got = 0;
54         while (length && m_head)
55         {
56             const size_t n = m_head.read(output, length);
57             output += n;
58             got += n;
59             length -= n;
60             if (m_head.length == 0)
61             {
62                 SecureQueueNode holder = m_head.m_next;
63                 .destroy(m_head);
64                 m_head = holder;
65             }
66         }
67         bytes_read += got;
68         return got;
69     }
70 
71     /*
72     * Read data, but do not remove it from queue
73     */
74     size_t peek(ubyte* output, size_t length, size_t offset = 0) const
75     {
76         SecureQueueNode current = cast(SecureQueueNode) m_head;
77         
78         while (offset && current)
79         {
80             if (offset >= current.length)
81             {
82                 offset -= current.length;
83                 current = current.m_next;
84             }
85             else
86                 break;
87         }
88         
89         size_t got = 0;
90         while (length && current)
91         {
92             const size_t n = current.peek(output, length, offset);
93             offset = 0;
94             output += n;
95             got += n;
96             length -= n;
97             current = current.m_next;
98         }
99         return got;
100     }
101 
102     /**
103     * Return how many bytes have been read so far.
104     */
105     size_t getBytesRead() const
106     {
107         return bytes_read;
108     }
109 
110     /*
111     * Test if the queue has any data in it
112     */
113     bool endOfData() const
114     {
115         return (size() == 0);
116     }
117 
118 
119     @property bool empty() const
120     {
121         return (size() == 0);
122     }
123 
124     /**
125     * Returns: number of bytes available in the queue
126     */
127     size_t size() const
128     {
129         SecureQueueNode current = cast(SecureQueueNode) m_head;
130         size_t count = 0;
131         
132         while (current)
133         {
134             count += current.length;
135             current = current.m_next;
136         }
137         return count;
138     }
139 
140     @property size_t length() const { return size(); } 
141 
142     override bool attachable() { return false; }
143 
144     /**
145     * SecureQueue default constructor (creates empty queue)
146     */
147     this()
148     {
149         bytes_read = 0;
150         Filter filt;
151         setNext(&filt, 0);
152         m_head = m_tail = new SecureQueueNode;
153     }
154 
155     /**
156     * SecureQueue copy constructor
157     * Params:
158     *  input = the queue to copy
159     */
160     this(SecureQueue input)
161     {
162         bytes_read = 0;
163         Filter filt;
164         setNext(&filt, 0);
165         
166         m_head = m_tail = new SecureQueueNode;
167         SecureQueueNode temp = input.m_head;
168         while (temp)
169         {
170             write(temp.m_buffer.ptr + temp.m_start, temp.m_end - temp.m_start);
171             temp = temp.m_next;
172         }
173     }
174 
175     ~this() { destroy(); }
176 
177     // Interface fallthrough
178     override void startMsg() { super.startMsg(); }
179     override void endMsg() { super.endMsg(); }
180     override string id() const { return ""; }
181     override void setNext(Filter* filters, size_t sz) { super.setNext(filters, sz); }
182 private:
183     size_t bytes_read;
184 
185     /*
186     * Destroy this SecureQueue
187     */
188     void destroy()
189     {
190         SecureQueueNode temp = m_head;
191         while (temp)
192         {
193             SecureQueueNode holder = temp.m_next;
194             .destroy(temp);
195             temp = holder;
196         }
197         m_head = m_tail = null;
198     }
199 
200     SecureQueueNode m_head;
201     SecureQueueNode m_tail;
202 }
203 
204 /**
205 * A node in a SecureQueue
206 */
207 class SecureQueueNode
208 {
209 public:
210 
211     this() 
212     { 
213         m_buffer = SecureVector!ubyte(DEFAULT_BUFFERSIZE);
214         m_next = null; 
215         m_start = m_end = 0; }
216     
217     ~this() { 
218         m_next = null; 
219         m_start = m_end = 0; 
220     }
221 
222     size_t write(const(ubyte)* input, size_t length)
223     {
224         size_t copied = std.algorithm.min(length, m_buffer.length - m_end);
225         copyMem(m_buffer.ptr + m_end, input, copied);
226         m_end += copied;
227         return copied;
228     }
229     
230     size_t read(ubyte* output, size_t length)
231     {
232         size_t copied = std.algorithm.min(length, m_end - m_start);
233         copyMem(output, m_buffer.ptr + m_start, copied);
234         m_start += copied;
235         return copied;
236     }
237     
238     size_t peek(ubyte* output, size_t length, size_t offset = 0)
239     {
240         const size_t left = m_end - m_start;
241         if (offset >= left) return 0;
242         size_t copied = std.algorithm.min(length, left - offset);
243         copyMem(output, m_buffer.ptr + m_start + offset, copied);
244         return copied;
245     }
246     
247     size_t size() const { return (m_end - m_start); }
248     @property size_t length() const { return size(); }
249 private:
250     SecureQueueNode m_next;
251     SecureVector!ubyte m_buffer;
252     size_t m_start, m_end;
253 }