1 /*
2     Copyright (c) 2019, DUNEX Contributors
3     Use, modification and distribution are subject to the
4     Boost Software License, Version 1.0.  (See accompanying file
5     COPYING or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7     dunex-auth: D toolkit to manage UNIX authentication
8     
9     Author: Clipsey
10 */
11 module dunex.auth.crypt;
12 import core.sys.posix.unistd : ccrypt = crypt;
13 import std..string;
14 import std.stdio : File;
15 import std.base64;
16 import std.format;
17 
18 /**
19     Implementation of base64 which uses '.' and '/'
20 
21     Reason behind this is the other POSIX compliant tools i've seen does this.
22 */
23 alias UBase64 = Base64Impl!('.', '/');
24 
25 /**
26     The UNIX password encryption function. 
27     It is based on the DES algorithm with 
28     variants intended (among other things) 
29     to discourage use of hardware 
30     implementations of a key search.
31 */
32 string crypt(string plaintext, string salt) {
33     return cast(string)ccrypt(plaintext.toStringz, salt.toStringz).fromStringz;
34 }
35 
36 /**
37     The available algorithms for crypto
38 */
39 enum Algorithm : string {
40     MD5 = "$1",
41     BlowfishA = "$2a",
42     BlowfishY = "$2y",
43     SHA256 = "$5",
44     SHA512 = "$6"
45 }
46 
47 /**
48     Make a UNIX salt with the specified algorithm
49 */
50 string makeSalt(Algorithm algo) {
51     
52     ubyte[] rand = cryptorandom(20);
53 
54     string salt = UBase64.encode(rand);
55 
56     return "%s$%s$".format(cast(string)algo, salt);
57 }
58 
59 /**
60     Gets sequence of cryptographically secure random bytes from /dev/urandom
61 */
62 ubyte[] cryptorandom(size_t length) {
63     
64     File rand = File("/dev/urandom", "r");
65     scope(exit) rand.close();
66 
67     ubyte[] data = new ubyte[length];
68     rand.rawRead(data);
69     return data;
70 }