1 /// Digests and ingests for various cryptography algorithms.
2 module tern.digest;
3 
4 import tern.traits;
5 import tern.serialization;
6 import tern.meta;
7 import std.meta;
8 
9 /// Attribute for marking a class as a digester, must implement `encrypt` or `hash  `
10 public enum digester;
11 
12 /// True if `T` is a digester of any kind.
13 public alias isDigest(T) = Alias!(seqContains!(digester, __traits(getAttributes, T)));
14 /// True if `T` is an encrypting digester.
15 public alias isEncryptingDigest(T) = Alias!(isDigest!T && hasStaticMember!(T, "encrypt"));
16 /// True if `T` is an hashing digester.
17 public alias isHashingDigest(T) = Alias!(isDigest!T && hasStaticMember!(T, "hash"));
18 
19 /* public class Digest(T, IV...)
20     if (isDigest!T)
21 {
22 protected:
23 final:
24     ubyte[] data;
25     IV iv;
26 
27 public:
28     this(IV iv)
29     {
30         this.iv = iv;
31     }
32 
33     auto digest(T)(size_t count = 1)
34     {
35         T[] ret;
36         foreach (i; 0..count)
37             ret ~= deserialize!T(serialize!true(digest(T.sizeof * count)));
38         return ret;
39     }
40 
41     auto digest(size_t size)
42     {
43         scope (exit) data = data[size..$];
44         static if (isEncryptingDigest!T)
45             return T.encrypt(*cast(ubyte[]*)data[0..size], iv);
46         else static if (isHashingDigest!T)
47             return T.hash(data[0..size], iv);
48     }
49 
50     auto digest(ARGS...)(size_t size, ARGS args)
51     {
52         auto data = this.data[0..size];
53         static if (isEncryptingDigest!T)
54             return T.encrypt(data, args);
55         else static if (isHashingDigest!T)
56             return T.hash(*cast(ubyte[]*)data[0..size], args);
57     }
58 
59     auto ingest(T)(size_t count = 1)
60     {
61         T[] ret;
62         foreach (i; 0..count)
63             ret ~= deserialize!T(serialize!true(ingest(T.sizeof * count)));
64         return ret;
65     }
66 
67     auto ingest(size_t size)
68     {
69         auto data = this.data[0..size];
70         scope (exit) data = data[size..$];
71         static if (isEncryptingDigest!T)
72             return T.decrypt(*cast(ubyte[]*)data[0..size], iv);
73         else static if (isHashingDigest!T)
74             return (serialize!true(T.hash(data[0..size], iv))).toHexString();
75     }
76 
77     auto ingest(ARGS...)(size_t size, ARGS args)
78     {
79         static if (isEncryptingDigest!T)
80             return T.decrypt(*cast(ubyte[]*)data[0..size], args);
81         else static if (isHashingDigest!T)
82             return (serialize!true(T.hash(data[0..size], args))).toHexString();
83     }
84 
85     void devour(ubyte[] data)
86     {
87         this.data ~= data;
88     }
89 
90     void drop(size_t size)
91     {
92         data = data[size..$];
93     }
94 } */
95 
96 public:
97 static:
98 /**
99  * Digests arguments by the given provider `T`.
100  * `T` must either have a `encrypt` or `hash` function present.
101  *
102  * Remarks:
103  *  - If `T` has a hash function present, the output will be the output of the hash function.
104  *  - If `T` has an encrypt function present, the output will be the output of the encryption function.
105  */
106 public auto digest(T, ARGS...)(ARGS args)
107     if (isEncryptingDigest!T)
108 {
109     return T.encrypt(args);
110 }
111 
112 /**
113  * Ingests arguments by the given provider `T`  
114  * `T` must either have a `decrypt` or `hash` function present.
115  *
116  * Remarks:
117  *  - If `T` has a hash function present, the output will be the output of the hash function serialized as a string.
118  *  - If `T` has a decrypt function present, the output will be the output of the decryption function.
119  */
120 public auto ingest(T, ARGS...)(ARGS args)
121     if (isEncryptingDigest!T)
122 {
123     return T.decrypt(args);
124 }
125 
126 /**
127  * Digests arguments by the given provider `T`  
128  * `T` must either have a `encrypt` or `hash` function present.
129  *
130  * Remarks:
131  *  - If `T` has a hash function present, the output will be the output of the hash function.
132  *  - If `T` has an encrypt function present, the output will be the output of the encryption function.
133  */
134 public auto digest(T, ARGS...)(ARGS args)
135     if (isHashingDigest!T)
136 {
137     return T.hash(args);
138 }
139 
140 /**
141  * Ingests arguments by the given provider `T`  
142  * `T` must either have a `decrypt` or `hash` function present.
143  *
144  * Remarks:
145  *  - If `T` has a hash function present, the output will be the output of the hash function serialized as a string.
146  *  - If `T` has a decrypt function present, the output will be the output of the decryption function.
147  */
148 public auto ingest(T, ARGS...)(ARGS args)
149     if (isHashingDigest!T)
150 {
151     return (serialize!true(T.hash(args))).toHexString();
152 }
153 
154 string toHexString(ubyte[] data) 
155 {
156     char hexDigit(ubyte value) 
157     {
158         return value < 10 ? cast(char)('0' + value) : cast(char)('A' + (value - 10));
159     }
160 
161     string ret;
162     foreach (b; data) 
163     {
164         ret ~= hexDigit(b >> 4);
165         ret ~= hexDigit(b & 0x0F);
166     }
167     return ret;
168 }
169