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 }