├── MD5.cpp ├── MD5.h ├── README.md └── examples └── MD5_Hash └── MD5_Hash.ino /MD5.cpp: -------------------------------------------------------------------------------- 1 | #include "MD5.h" 2 | 3 | MD5::MD5() 4 | { 5 | //nothing 6 | return; 7 | } 8 | 9 | char* MD5::make_digest(const unsigned char *digest, int len) /* {{{ */ 10 | { 11 | char * md5str = (char*) malloc(sizeof(char)*(len*2+1)); 12 | static const char hexits[17] = "0123456789abcdef"; 13 | int i; 14 | 15 | for (i = 0; i < len; i++) { 16 | md5str[i * 2] = hexits[digest[i] >> 4]; 17 | md5str[(i * 2) + 1] = hexits[digest[i] & 0x0F]; 18 | } 19 | md5str[len * 2] = '\0'; 20 | return md5str; 21 | } 22 | 23 | /* 24 | * The basic MD5 functions. 25 | * 26 | * E and G are optimized compared to their RFC 1321 definitions for 27 | * architectures that lack an AND-NOT instruction, just like in Colin Plumb's 28 | * implementation. 29 | * E() has been used instead of F() because F() is already defined in the Arduino core 30 | */ 31 | #define E(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) 32 | #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) 33 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 34 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) 35 | 36 | /* 37 | * The MD5 transformation for all four rounds. 38 | */ 39 | #define STEP(f, a, b, c, d, x, t, s) \ 40 | (a) += f((b), (c), (d)) + (x) + (t); \ 41 | (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ 42 | (a) += (b); 43 | 44 | /* 45 | * SET reads 4 input bytes in little-endian byte order and stores them 46 | * in a properly aligned word in host byte order. 47 | * 48 | * The check for little-endian architectures that tolerate unaligned 49 | * memory accesses is just an optimization. Nothing will break if it 50 | * doesn't work. 51 | */ 52 | #if defined(__i386__) || defined(__x86_64__) || defined(__vax__) 53 | # define SET(n) \ 54 | (*(MD5_u32plus *)&ptr[(n) * 4]) 55 | # define GET(n) \ 56 | SET(n) 57 | #else 58 | # define SET(n) \ 59 | (ctx->block[(n)] = \ 60 | (MD5_u32plus)ptr[(n) * 4] | \ 61 | ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ 62 | ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ 63 | ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) 64 | # define GET(n) \ 65 | (ctx->block[(n)]) 66 | #endif 67 | 68 | /* 69 | * This processes one or more 64-byte data blocks, but does NOT update 70 | * the bit counters. There are no alignment requirements. 71 | */ 72 | const void *MD5::body(void *ctxBuf, const void *data, size_t size) 73 | { 74 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 75 | const unsigned char *ptr; 76 | MD5_u32plus a, b, c, d; 77 | MD5_u32plus saved_a, saved_b, saved_c, saved_d; 78 | 79 | ptr = (unsigned char*)data; 80 | 81 | a = ctx->a; 82 | b = ctx->b; 83 | c = ctx->c; 84 | d = ctx->d; 85 | 86 | do { 87 | saved_a = a; 88 | saved_b = b; 89 | saved_c = c; 90 | saved_d = d; 91 | 92 | /* Round 1 93 | * E() has been used instead of F() because F() is already defined in the Arduino core 94 | */ 95 | STEP(E, a, b, c, d, SET(0), 0xd76aa478, 7) 96 | STEP(E, d, a, b, c, SET(1), 0xe8c7b756, 12) 97 | STEP(E, c, d, a, b, SET(2), 0x242070db, 17) 98 | STEP(E, b, c, d, a, SET(3), 0xc1bdceee, 22) 99 | STEP(E, a, b, c, d, SET(4), 0xf57c0faf, 7) 100 | STEP(E, d, a, b, c, SET(5), 0x4787c62a, 12) 101 | STEP(E, c, d, a, b, SET(6), 0xa8304613, 17) 102 | STEP(E, b, c, d, a, SET(7), 0xfd469501, 22) 103 | STEP(E, a, b, c, d, SET(8), 0x698098d8, 7) 104 | STEP(E, d, a, b, c, SET(9), 0x8b44f7af, 12) 105 | STEP(E, c, d, a, b, SET(10), 0xffff5bb1, 17) 106 | STEP(E, b, c, d, a, SET(11), 0x895cd7be, 22) 107 | STEP(E, a, b, c, d, SET(12), 0x6b901122, 7) 108 | STEP(E, d, a, b, c, SET(13), 0xfd987193, 12) 109 | STEP(E, c, d, a, b, SET(14), 0xa679438e, 17) 110 | STEP(E, b, c, d, a, SET(15), 0x49b40821, 22) 111 | 112 | /* Round 2 */ 113 | STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) 114 | STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) 115 | STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) 116 | STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) 117 | STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) 118 | STEP(G, d, a, b, c, GET(10), 0x02441453, 9) 119 | STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) 120 | STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) 121 | STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) 122 | STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) 123 | STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) 124 | STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) 125 | STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) 126 | STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) 127 | STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) 128 | STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) 129 | 130 | /* Round 3 */ 131 | STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) 132 | STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) 133 | STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) 134 | STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) 135 | STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) 136 | STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) 137 | STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) 138 | STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) 139 | STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) 140 | STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) 141 | STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) 142 | STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) 143 | STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) 144 | STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) 145 | STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) 146 | STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) 147 | 148 | /* Round 4 */ 149 | STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) 150 | STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) 151 | STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) 152 | STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) 153 | STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) 154 | STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) 155 | STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) 156 | STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) 157 | STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) 158 | STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) 159 | STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) 160 | STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) 161 | STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) 162 | STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) 163 | STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) 164 | STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) 165 | 166 | a += saved_a; 167 | b += saved_b; 168 | c += saved_c; 169 | d += saved_d; 170 | 171 | ptr += 64; 172 | } while (size -= 64); 173 | 174 | ctx->a = a; 175 | ctx->b = b; 176 | ctx->c = c; 177 | ctx->d = d; 178 | 179 | return ptr; 180 | } 181 | 182 | void MD5::MD5Init(void *ctxBuf) 183 | { 184 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 185 | ctx->a = 0x67452301; 186 | ctx->b = 0xefcdab89; 187 | ctx->c = 0x98badcfe; 188 | ctx->d = 0x10325476; 189 | 190 | ctx->lo = 0; 191 | ctx->hi = 0; 192 | 193 | memset(ctx->block, 0, sizeof(ctx->block)); 194 | memset(ctx->buffer, 0, sizeof(ctx->buffer)); 195 | } 196 | 197 | void MD5::MD5Update(void *ctxBuf, const void *data, size_t size) 198 | { 199 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 200 | MD5_u32plus saved_lo; 201 | MD5_u32plus used, free; 202 | 203 | saved_lo = ctx->lo; 204 | if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) { 205 | ctx->hi++; 206 | } 207 | ctx->hi += size >> 29; 208 | 209 | used = saved_lo & 0x3f; 210 | 211 | if (used) { 212 | free = 64 - used; 213 | 214 | if (size < free) { 215 | memcpy(&ctx->buffer[used], data, size); 216 | return; 217 | } 218 | 219 | memcpy(&ctx->buffer[used], data, free); 220 | data = (unsigned char *)data + free; 221 | size -= free; 222 | body(ctx, ctx->buffer, 64); 223 | } 224 | 225 | if (size >= 64) { 226 | data = body(ctx, data, size & ~(size_t)0x3f); 227 | size &= 0x3f; 228 | } 229 | 230 | memcpy(ctx->buffer, data, size); 231 | } 232 | 233 | void MD5::MD5Final(unsigned char *result, void *ctxBuf) 234 | { 235 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 236 | MD5_u32plus used, free; 237 | 238 | used = ctx->lo & 0x3f; 239 | 240 | ctx->buffer[used++] = 0x80; 241 | 242 | free = 64 - used; 243 | 244 | if (free < 8) { 245 | memset(&ctx->buffer[used], 0, free); 246 | body(ctx, ctx->buffer, 64); 247 | used = 0; 248 | free = 64; 249 | } 250 | 251 | memset(&ctx->buffer[used], 0, free - 8); 252 | 253 | ctx->lo <<= 3; 254 | ctx->buffer[56] = ctx->lo; 255 | ctx->buffer[57] = ctx->lo >> 8; 256 | ctx->buffer[58] = ctx->lo >> 16; 257 | ctx->buffer[59] = ctx->lo >> 24; 258 | ctx->buffer[60] = ctx->hi; 259 | ctx->buffer[61] = ctx->hi >> 8; 260 | ctx->buffer[62] = ctx->hi >> 16; 261 | ctx->buffer[63] = ctx->hi >> 24; 262 | 263 | body(ctx, ctx->buffer, 64); 264 | 265 | result[0] = ctx->a; 266 | result[1] = ctx->a >> 8; 267 | result[2] = ctx->a >> 16; 268 | result[3] = ctx->a >> 24; 269 | result[4] = ctx->b; 270 | result[5] = ctx->b >> 8; 271 | result[6] = ctx->b >> 16; 272 | result[7] = ctx->b >> 24; 273 | result[8] = ctx->c; 274 | result[9] = ctx->c >> 8; 275 | result[10] = ctx->c >> 16; 276 | result[11] = ctx->c >> 24; 277 | result[12] = ctx->d; 278 | result[13] = ctx->d >> 8; 279 | result[14] = ctx->d >> 16; 280 | result[15] = ctx->d >> 24; 281 | 282 | memset(ctx, 0, sizeof(*ctx)); 283 | } 284 | unsigned char* MD5::make_hash(char *arg) 285 | { 286 | MD5_CTX context; 287 | unsigned char * hash = (unsigned char *) malloc(16); 288 | MD5Init(&context); 289 | MD5Update(&context, arg, strlen(arg)); 290 | MD5Final(hash, &context); 291 | return hash; 292 | } 293 | unsigned char* MD5::make_hash(char *arg,size_t size) 294 | { 295 | MD5_CTX context; 296 | unsigned char * hash = (unsigned char *) malloc(16); 297 | MD5Init(&context); 298 | MD5Update(&context, arg, size); 299 | MD5Final(hash, &context); 300 | return hash; 301 | } 302 | 303 | -------------------------------------------------------------------------------- /MD5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_h 2 | #define MD5_h 3 | 4 | #include "Arduino.h" 5 | 6 | /* 7 | * This is an OpenSSL-compatible implementation of the RSA Data Security, 8 | * Inc. MD5 Message-Digest Algorithm (RFC 1321). 9 | * 10 | * Written by Solar Designer in 2001, and placed 11 | * in the public domain. There's absolutely no warranty. 12 | * 13 | * This differs from Colin Plumb's older public domain implementation in 14 | * that no 32-bit integer data type is required, there's no compile-time 15 | * endianness configuration, and the function prototypes match OpenSSL's. 16 | * The primary goals are portability and ease of use. 17 | * 18 | * This implementation is meant to be fast, but not as fast as possible. 19 | * Some known optimizations are not included to reduce source code size 20 | * and avoid compile-time configuration. 21 | */ 22 | 23 | /* 24 | * Updated by Scott MacVicar for arduino 25 | * 26 | */ 27 | 28 | #include 29 | 30 | typedef unsigned long MD5_u32plus; 31 | 32 | typedef struct { 33 | MD5_u32plus lo, hi; 34 | MD5_u32plus a, b, c, d; 35 | unsigned char buffer[64]; 36 | MD5_u32plus block[16]; 37 | } MD5_CTX; 38 | 39 | class MD5 40 | { 41 | public: 42 | MD5(); 43 | static unsigned char* make_hash(char *arg); 44 | static unsigned char* make_hash(char *arg,size_t size); 45 | static char* make_digest(const unsigned char *digest, int len); 46 | static const void *body(void *ctxBuf, const void *data, size_t size); 47 | static void MD5Init(void *ctxBuf); 48 | static void MD5Final(unsigned char *result, void *ctxBuf); 49 | static void MD5Update(void *ctxBuf, const void *data, size_t size); 50 | }; 51 | 52 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is an MD5 library for the Arduino, based on scottmac's MD5 library, which you can find here: 2 | https://github.com/scottmac/arduino 3 | 4 | I created this because I was having a really hard time finding an easy-to-install and use libray for the Arduino, 5 | so I decided to make my own. There is an example on how to use it. 6 | 7 | ### Installation 8 | Create a folder named _MD5_ in the _libraries_ folder inside your Arduino sketch folder. If the 9 | libraries folder doesn't exist, create it. Then copy everything inside. (re)launch the Arduino IDE. 10 | 11 | You're done. Time for a mojito 12 | 13 | ### Usage 14 | 15 | If you create md5 Hashes in a loop you must give the Memory back to the System 16 | ``` 17 | unsigned char* hash=MD5::make_hash("hello world"); 18 | //generate the digest (hex encoding) of our hash 19 | char *md5str = MD5::make_digest(hash, 16); 20 | //print it on our serial monitor 21 | Serial.println(md5str); 22 | //Give the Memory back to the System if you run the md5 Hash generation in a loop 23 | free(md5str); 24 | //free dynamically allocated 16 byte hash from make_hash() 25 | free(hash); 26 | ``` 27 | -------------------------------------------------------------------------------- /examples/MD5_Hash/MD5_Hash.ino: -------------------------------------------------------------------------------- 1 | #include 2 | /* 3 | This is en example of how to use my MD5 library. It provides two 4 | easy-to-use methods, one for generating the MD5 hash, and the second 5 | one to generate the hex encoding of the hash, which is frequently used. 6 | */ 7 | void setup() 8 | { 9 | //initialize serial 10 | Serial.begin(9600); 11 | //give it a second 12 | delay(1000); 13 | //generate the MD5 hash for our string 14 | unsigned char* hash=MD5::make_hash("hello world"); 15 | //generate the digest (hex encoding) of our hash 16 | char *md5str = MD5::make_digest(hash, 16); 17 | free(hash); 18 | //print it on our serial monitor 19 | Serial.println(md5str); 20 | //Give the Memory back to the System if you run the md5 Hash generation in a loop 21 | free(md5str); 22 | } 23 | 24 | void loop() 25 | { 26 | } 27 | --------------------------------------------------------------------------------