-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.json
218 lines (218 loc) · 64.6 KB
/
index.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
[
{
"uri": "https://libpasta.github.io/libpasta-dev/contributing/",
"title": "Contributing",
"tags": [],
"description": "",
"content": "libpasta is still at an early stage of development and is looking for contribution in all areas.\nSome specific areas which are looking for contribution:\n Improving these docs - source The core Rust library - source Adding more languages - see adding languages Writing more utility tools - source "
},
{
"uri": "https://libpasta.github.io/introduction/",
"title": "Introduction",
"tags": [],
"description": "",
"content": " Chapter 1 Introduction Introduction to libpasta.\n"
},
{
"uri": "https://libpasta.github.io/other-languages/overview/",
"title": "Overview",
"tags": [],
"description": "",
"content": "Our goal is for libpasta to be the clear choice for any developers requiring secure password storage. Hence we have initial support for a number of languages.\nFor any missing languages, please open an issue or click \u0026ldquo;Edit this page\u0026rdquo; and submit a pull request.\nHere we list the support:\n Language Supported? Repository Documentation C Y TODO TODO Java Y Link Link PHP Y TODO TODO Python Y Link TODO Ruby Y TODO TODO Rust Y (Native) Link Link "
},
{
"uri": "https://libpasta.github.io/libpasta-dev/adding-languages/",
"title": "Adding Languages",
"tags": [],
"description": "",
"content": "Our initial support for other languages is through the use of SWIG.\nSo far, this means we have simple bindings for C, Java, PHP, python, and Ruby.\nIf you want to add new language bindings, this is a good place to start.\nThe SWIG specification for libpasta reveals the simplicity of the API, and a few important caveats:\n# in pasta.h #include \u0026lt;stdbool.h\u0026gt;extern char * hash_password(const char *password); extern bool verify_password(const char* hash, const char *password); extern void free_string(const char *); extern char * read_password(const char *prompt); These bind to the functions exported by the libpasta-ffi crate.\n# in pasta.i %module pasta %{ #include \u0026lt;pasta.h\u0026gt; %} %typemap(newfree) char * \u0026#34;free_string($1);\u0026#34;; %newobject hash_password; %newobject read_password; %pragma(java) jniclasscode=%{ static { try { System.loadLibrary(\u0026#34;pasta_jni\u0026#34;); } catch (UnsatisfiedLinkError e) { System.err.println(\u0026#34;Native code library failed to load. \\n\u0026#34; + e); System.exit(1); } } %} #include \u0026lt;pasta.h\u0026gt; An important caveat, and reason why these bindings should be preferred, is that the values returned by hash_password and read_password are technically still Rust CStrings. Although these are in the correct layout to be read as string pointers in C, we must take care to return the pointer to Rust so that it can handle freeing the CString. Otherwise we are left with a memory leak.\nNotice that the SWIG bindings have handled this: on returning a CString, the bindings create a new object, and then call free_string on the pointer.\n"
},
{
"uri": "https://libpasta.github.io/advanced/",
"title": "Advanced Usage",
"tags": [],
"description": "",
"content": " Chapter 2 Advanced Usage Explore the tools provided by libpasta to help you manage your passwords.\n"
},
{
"uri": "https://libpasta.github.io/other-languages/",
"title": "Other Languages",
"tags": [],
"description": "",
"content": " Chapter 3 Other Languages Explore the language bindings already supported by libpasta.\n"
},
{
"uri": "https://libpasta.github.io/technical-details/",
"title": "Technical Details",
"tags": [],
"description": "",
"content": " Chapter 4 Additional Technical Details Here we give some additional information about the techniques used.\n"
},
{
"uri": "https://libpasta.github.io/introduction/what-is-libpasta/",
"title": "What is libpasta?",
"tags": [],
"description": "",
"content": " Password breaches have become a regular occurrence. See: Yahoo (twice), LinkedIn, Adobe, Ashley Madison, and a whole lot more.\nFurthermore, with the exception of Yahoo who eventually migrated to bcrypt in 2013, the above examples doubles as a list of \u0026ldquo;how NOT to do password storage\u0026rdquo;: simple hashing, unsalted values, misuse of encryption, and failed password migration. (For more information on why these are bad, see our introduction to password hashing theory).\nThere are two possible interpretations here: first, companies do not put adequate resources in securing passwords; and secondly, getting password hashing right is hard. Furthermore, even if you have followed previous best practice, keeping it right is another technical challenge: algorithm choices, security levels, parameter selection change regularly.\nlibpasta - making passwords painless This library aims to be an all-in-one solution for password storage. In particular, we aim to provide:\n Easy-to-use password storage with strong defaults. Tools to provide parameter tuning for different use cases. Automatic migration of passwords to new algorithms. Cross-platform builds and cross-language bindings. Secure by default libpasta is ready to work at a production level straight out of the box. We hide any unnecessary decisions from the developer. Together with the support for migrating passwords, libpasta provides a streamlined, easy, and secure password management solution.\nCurrently, the algorithm favoured by libpasta is scrypt. For more details, see algorithm choice.\nEasy password migration Many developers still use insecure password hashing systems, despite it causing embarrassing and significant vulnerabilities should a leak occur.\nOur aim is to help everyone adopt modern algorithms and associated best practices. Hence we have designed libpasta with built-in support for easy password migration.\nThis allows you to migrate an existing password hash database to secure algorithms, without inconveniencing users with password resets. Furthermore, having convenient migration tools makes it easier to keep you up-to-date with what hashing parameters should be as computer performance increases.\nSee basic usage for an example of migrating passwords, or advanced usage for more details.\nTunable Password hashing is relatively slow by design, and setting parameters (the cost of computing the hash) too low can be a vulnerability. Of course this has to be balanced against performance of your libpasta-using application. For times when the default parameters are not sufficient, libpasta helps developers pick good parameters.\nThe tuning tool measures the performance of your system to suggest parameters, as well as doing some sanity checks based on the specifications of the system. The tool will help you avoid setting parameters too aggressively\nSee tuning for more details.\nCross-platform and cross-language While the main library is written in Rust, thanks to the C-style ABI that is exported by Rust libraries, we are able to support many different languages. Similarly, Rust supports compilation over a number of platforms.\nFor more information, see other languages.\n"
},
{
"uri": "https://libpasta.github.io/technical-details/algorithm-choice/",
"title": "Algorithm Selection",
"tags": [],
"description": "",
"content": " Currently, we use scrypt as the default algorithm in libpasta. The default parameters are:\nN: 2^15 r: 8 p: 1 This results in a memory requirement of approximately 32MiB and about 0.1 seconds to compute. For many systems, this can be increased, and we suggest using the tuning tools to choose suitable parameters.\nFor more information on the scrypt parameters, see: https://blog.filippo.io/the-scrypt-parameters/\nWhy scrypt? Scrypt was introduced in 2009 as a memory-hard hash function, designed to reduce the advantage gained by using custom hardware (e.g. ASICs) over general purpose CPUs. Recently, it was shown in [ACPRT16] that scrypt is in fact optimally memory-hard, when measured as the cumulative memory requirement of the algorithm (i.e., the \u0026ldquo;area\u0026rdquo; of the memory/time graph). While this result does not comprehensively thwart ASIC attacks, it is a definite step in the right direction for scrypt.\nOther memory-hard hash functions include Argon2, which was the winner of the recent password hashing competition. Argon2 currently has three modes: data-dependent Argon2d, data-independent Argon2i, and a mix of the two, Argon2id.\nBoth scrypt and Argon2 with decent parameter choices are vastly preferable to using any of the older algorithms, bcrypt, PBKDF2, etc. Therefore we are mostly interested in addressing Argon2 vs scrypt.\nscrypt vs Argon2 tl:dr Argon2 is more modern, with nice features and a higher potential, but scrypt is the conservative choice.\nIn detail:\nscrypt has been around for longer, giving it more exposure, and more time to iron out any bugs or kinks. Furthermore, recent theoretical results about the memory hardness shows scrypt is well-designed and reduces the chance of a catastrophic failure.\nOn the other hand, scrypt has two large weaknesses. The algorithm is data-dependent which means there is the possibility of a side-channel attack (cache timings across VMs for example). In addition, scrypt has a trivial time-memory tradeoff attack, which means that ASICs still offer a significant speedup.\nArgon2 was recently chosen as the password-hashing competition winner. It has easily tunable parameters, and a number of modes suitable for different purposes. Argon2d is data-dependent and has a higher (potential) memory hardness, whereas Argon2i is data-independent and aims to eliminate side- channel attacks. Argon2id combines the two, attempting to offer the best of both worlds.\nHowever, Argon2 has only recently been developed/specified/implemented and is still in draft status with the CFRG. Furthermore, there are some recent attacks which are resulting in tweaking of the recommended parameter choices. Hence we opt for scrypt as the conservative choice.\nFuture possibility: support a scrypt-argon2 hybrid mode, e.g. a few rounds of Argon2i followed by scrypt.\n"
},
{
"uri": "https://libpasta.github.io/introduction/basic-usage/",
"title": "Basic Usage",
"tags": [],
"description": "",
"content": " Here we give an overview of the core functionality of libpasta. Examples can be viewed in different languages, with the full list of language support found in other languages.\nThe full Rust API documentation can be found here.\nPassword Hashes A common scenario is that a particular user has password, which a service will check on each login to authenticate the user.\n Java Python Ruby Rust import io.github.libpasta.pasta; public class hash { public static void main(String argv[]) { String password = pasta.read_password(\u0026#34;Please enter your password:\u0026#34;); String hash = pasta.hash_password(password); System.out.println(\u0026#34;The hashed password is: \u0026#34; + hash); } } from libpasta import * password = read_password(\u0026#34;Please enter your password:\u0026#34;) hash = hash_password(password) print(\u0026#34;The hashed password is: \u0026#34;, hash) require \u0026#39;libpasta\u0026#39; password = Pasta::read_password \u0026#34;Please enter your password:\u0026#34; hash = Pasta::hash_password(password) puts \u0026#34;The hashed password is: \u0026#34;, hash extern crate libpasta; // We re-export the rpassword crate for CLI password input. use libpasta::rpassword::*; fn main() { let password = prompt_password_stdout(\u0026#34;Please enter your password:\u0026#34;).unwrap(); let password_hash = libpasta::hash_password(\u0026amp;password); println!(\u0026#34;The hashed password is: \u0026#39;{}\u0026#39;\u0026#34;, password_hash); } The above code randomly generates a salt, and outputs the hash in the following format: $$scrypt-mcf$log_n=14,r=8,p=1$pfJFg/hVSthuA5l....\nDetails for how this is serialized can be found in the technical details chapter. This adheres to libpasta\u0026rsquo;s strong defaults principle.\nHowever, for using libpasta one only needs to know that hash_password outputs a variable-length string.\nVerifying passwords Now that you have the hashed output, verifying that an inputted password is correct can be done as follows:\n Java Python Ruby Rust import io.github.libpasta.pasta; public class verify { private String password_hash; public void authUser() { String password = pasta.read_password(\u0026#34;Enter password:\u0026#34;); if(pasta.verify_password(self.password_hash, password)) { System.out.println(\u0026#34;The password is correct!\u0026#34;); // ~\u0026gt; Handle correct password } else { System.out.println(\u0026#34;Incorrect password.\u0026#34;); // ~\u0026gt; Handle incorrect password } } } from libpasta import * class User: password_hash = \u0026#34;\u0026#34; def auth_user(): password = read_password(\u0026#34;Enter password:\u0026#34;) if verify_password(self.password_hash, password): print(\u0026#34;The password is correct!\u0026#34;) # ~\u0026gt; Handle correct password else: print(\u0026#34;Incorrect password.\u0026#34;) # ~\u0026gt; Handle incorrect password require \u0026#39;libpasta\u0026#39; class User attr_accessor :pw_hash @pw_hash = \u0026#34;\u0026#34; def auth_user password = Pasta::read_password(\u0026#34;Enter password: \u0026#34;) if Pasta::verify_password(self.pw_hash, password) puts \u0026#34;The password is correct!\u0026#34; # ~\u0026gt; Handle correct password else puts \u0026#34;Incorrect password.\u0026#34; # ~\u0026gt; Handle incorrect password end end end extern crate libpasta; use libpasta::rpassword::*; struct User { // ... password_hash: String, } fn auth_user(user: \u0026amp;User) { let password = prompt_password_stdout(\u0026#34;Enter password:\u0026#34;).unwrap(); if libpasta::verify_password(\u0026amp;user.password_hash, \u0026amp;password) { println!(\u0026#34;The password is correct!\u0026#34;); // ~\u0026gt; Handle correct password } else { println!(\u0026#34;Incorrect password.\u0026#34;); // ~\u0026gt; Handle incorrect password } } Password migration One of the key features of libpasta is the ability to easily migrate passwords to new algorithms.\nSuppose we previously have bcrypt hashes in the following form: $2a$10$175ikf/E6E.73e83..... This a bcrypt hash, structured as $\u0026lt;bcrypt identifier\u0026gt;$\u0026lt;cost\u0026gt;$\u0026lt;salthash\u0026gt;.\nlibpasta includes a simple work flow for migrating passwords to a new algorithm (or new parameterization of an existing algorithm).\nFirst, wrap existing hashes in the new algorithm to ensure their security immediately. Second, as users log in, update the wrapped hashes to just use the new algorithm. Wrapping simply takes an existing hash and re-hashes it with the new algorithm.\nThe following code first wraps an existing hash, and then a move to just using the new algorithm:\n Java Python Ruby Rust import io.github.libpasta.pasta; import io.github.libpasta.HashUpdate; class User { String pw_hash; public boolean auth_user() { String pw = pasta.read_password(\u0026#34;Enter password:\u0026#34;); HashUpdate res = pasta.verify_password_update_hash(pw_hash, pw); switch (res.getTag()) { case Updated: pw_hash = res.getUpdated(); case Ok: return true; } return false; } public static void migrate_users(User[] users) { for(User user : users) { HashUpdate res = pasta.migrate_hash(user.pw_hash); switch (res.getTag()) { case Updated: user.pw_hash = res.getUpdated(); case Ok: System.out.println(\u0026#34;Password correct\u0026#34;); break; case Failed: System.out.println(\u0026#34;Password incorrect\u0026#34;); } } } } from libpasta import * class User: def auth_user(self): pw = read_password(\u0026#34;Enter password\u0026#34;) res = verify_password_update_hash(self.pw_hash, pw) if res.tag == HashUpdate.Updated: self.pw_hash = res.Updated return true elif res.tag == HashUpdate.Ok: return true else: return false def migrate_users(users): for user in users: res = migrate_hash(user.pw_hash) if res.tag == HashUpdate.Updated: user.pw_hash = res.updated require \u0026#39;libpasta\u0026#39; class User attr_accessor :pw_hash @pw_hash = \u0026#34;\u0026#34; def auth_user pw = Pasta::read_password(\u0026#34;Enter password: \u0026#34;) res = Pasta::verify_password_update_hash(self.pw_hash, pw) case res.tag when Pasta::HashUpdate::Updated self.pw_hash = res.updated return true when Pasta::HashUpdate::Ok return true else return false end end end def migrate_users(users) for user in users do res = Pasta::migrate_hash(user.pw_hash) if res.tag.eql? Pasta::HashUpdate::Updated user.pw_hash = res.updated end end end extern crate libpasta; use libpasta::rpassword::*; use libpasta::{migrate_hash, HashUpdate}; struct User { // ... password_hash: String, } fn migrate_users(users: Vec\u0026lt;\u0026amp;mut User\u0026gt;) { // Step 1: Wrap old hash for user in users { let hash = user.password_hash; if let HashUpdate::Verified(Some(new_hash)) = migrate_hash(hash) { user.password_hash = new_hash; } } } fn auth_user(user: \u0026amp;mut User) { // Step 2: Update algorithm during log in let password = prompt_password_stdout(\u0026#34;Enter password:\u0026#34;).unwrap(); match libpasta::verify_password_update_hash(\u0026amp;user.password_hash, password) { HashUpdate::Verified(res) =\u0026gt; { if let Some(new_hash) = res { user.password_hash = new_hash; } println!(\u0026#34;Password correct, new hash: \\n{}\u0026#34;, user.password_hash); }, HashUpdate::Failed =\u0026gt; { println!(\u0026#34;Password incorrect, hash unchanged: \\n{}\u0026#34;, user.password_hash); } } } In the first step, we do not need the user\u0026rsquo;s password (and can therefore apply this to all user passwords when desired). However, the password hash is now comprised of both a bcrypt computation AND an argon2 computation.\nIn the second step, if the user correctly enters their password, then a new hash is computed from scratch with a fresh salt using the new algorithm. This requires updating the stored version of the hash.\nMore detailed information of password migration can be found here.\nBasic configuration libpasta is designed to work out-of-the box with strong defaults. However, other configurations are supported through use of the Config object. In particular, this is necessary to use keyed functions.\nThis comes with the additional overheard that the config must be explicitly used.\nFor example, suppose we wish to use bcrypt with cost=15 as the default algorithm.\n Java Python Ruby Rust import io.github.libpasta.Bcrypt; import io.github.libpasta.Config; public class config { public static void main(String[] args) { Bcrypt b = new Bcrypt(15); Config cfg = Config.with_primitive(b); String hash = cfg.hash_password(\u0026#34;hunter2\u0026#34;); System.out.println(\u0026#34;The hashed password is: \u0026#34; + hash); } } from libpasta import * config = Config.with_primitive(Bcrypt(15)) pw_hash = config.hash_password(\u0026#34;hunter2\u0026#34;) print(\u0026#34;The hashed password is: \u0026#34;, pw_hash) require \u0026#39;libpasta\u0026#39; config = Pasta::Config.with_primitive(Pasta::Bcrypt.new(15)) pw_hash = config.hash_password(\u0026#34;hunter2\u0026#34;) puts \u0026#34;The hashed password is: \u0026#34;, pw_hash extern crate libpasta; use libpasta::primitives::Bcrypt; use libpasta::config::Config; fn main() { let config = Config::with_primitive(Bcrypt::new(15)); let password_hash = config.hash_password(\u0026#34;hunter2\u0026#34;); println!(\u0026#34;The hashed password is: \u0026#39;{}\u0026#39;\u0026#34;, password_hash); // Prints bcrypt hash } Additionally, values may be set using a configuration file. Written in YAML, these look as follows:\ndefault: Custom keyed: ~ primitive: id: \u0026#34;scrypt\u0026#34; params: ln: 11 r: 8 p: 1 This specifies the algorithm to use, in this case, scrypt. Similar to the above, to use this config use the Config::from_file method.\nlibpasta also has a parameter selection tool which can optionally output configuration values.\n"
},
{
"uri": "https://libpasta.github.io/other-languages/c/",
"title": "C",
"tags": [],
"description": "",
"content": "We can use the FFI definitions output by Rust directly in C code. However, unlike with the SWIG bindings, we are required to manually free the strings after use, as in the following simple example.\n### in pasta.h #include \u0026lt;stdbool.h\u0026gt; extern char * hash_password(const char *password); extern bool verify_password(const char* hash, const char *password); extern void free_string(const char *); extern char * read_password(const char *prompt);#include \u0026#34;pasta.h\u0026#34;#include \u0026lt;stdio.h\u0026gt; int main(void) { char *hash, *password; hash = hash_password(\u0026#34;hello123\u0026#34;); password = read_password(\u0026#34;Please enter the password (hint: hello123):\u0026#34;); if (verify_password(hash, password)) { printf(\u0026#34;Correct password\\n\u0026#34;); } else { printf(\u0026#34;Sorry, that is incorrect\\n\u0026#34;); } free_string(hash); free_string(password); return 0; } Which is compiled in the usual way:\n$ ls pasta.h test.c $ gcc test.c -lpasta -otest $ ./test Please enter the password (hint: hello123): Correct password"
},
{
"uri": "https://libpasta.github.io/libpasta-dev/",
"title": "Developing libpasta",
"tags": [],
"description": "",
"content": " Chapter 5 Developing libpasta Guide for developers wishing to work on/expand libpasta.\n"
},
{
"uri": "https://libpasta.github.io/other-languages/java/",
"title": "Java",
"tags": [],
"description": "",
"content": "There is currently support for the base functionality in Java.\nThe library can be obtained by following the instruction in the repository. The simplest being to obtain the precompiled jar file from the releases page.\nOnce obtained a simple example such as the following can be constructed:\nimport io.github.libpasta.*; public class test { public static void main(String argv[]) { String hash = pasta.hash_password(\u0026#34;hello123\u0026#34;); String password = pasta.read_password(\u0026#34;Please enter the password (hint: hello123):\u0026#34;); if (pasta.verify_password(hash, password)) { System.out.println(\u0026#34;Correct password\\n\u0026#34;); } else { System.out.println(\u0026#34;Sorry, that is incorrect\\n\u0026#34;); } } } And building the example with:\n$ javac -cp .:libpasta-java.{version}.jar test.java $ java -cp .:libpasta.jar test Please enter the password (hint: hello123): Correct password If you see the following:\nSLF4J: Failed to load class \u0026quot;org.slf4j.impl.StaticLoggerBinder\u0026quot;. SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Make sure to add a SLF4J logger jar to the classpath. For example, the slf4j-nop logger, which simply ignores all logging messages, can be run with\n$ java -cp .:libpasta.jar:slf4j-nop-1.7.25.jar test"
},
{
"uri": "https://libpasta.github.io/advanced/keyed/",
"title": "Keyed Hashes",
"tags": [],
"description": "",
"content": "We are currently developing support for keyed hashes: whether through HMAC or encrypted values. For now, keys are generated and stored locally in memory in the running instance, which means that any passwords which are stored while the application is running will be useless if the application terminates and destroys the keys.\nThe goal is for this structure to be flexible to any kinds of environments with different sources.\nFor example, the following code configures a key for use in libpasta and sets up HMAC to be used as a wrapping function:\nuse libpasta::primitives::hmac::Hmac; use libpasta::config::Config; let mut config = Config::default(); // Some proper way of getting a key let key = b\u0026#34;yellow submarine\u0026#34;; // The key source used by config is responsible for the key identifier let key_id = config.add_key(key); // Construct an HMAC instance and use this as the outer configuration let keyed_function = Hmac::with_key_id(\u0026amp;digest::SHA256, \u0026amp;key_id); config.set_keyed_hash(keyed_function); Using config.hash_function will first hash using the default algorithm, and then afterwards apply the HMAC to the output hash.\nAlternate key sources can be specified by implementing the key::Store trait. In the following example, we create a (bad!) key store, which uses a static key for any identifier passed to it.\nextern crate libpasta; extern crate ring; use libpasta::key; use ring::digest; #[derive(Debug)] struct StaticSource(\u0026amp;\u0026#39;static [u8; 16]); static STATIC_SOURCE: StaticSource = StaticSource(b\u0026#34;ThisIsAStaticKey\u0026#34;); impl key::Store for StaticSource { /// Insert a new key into the `Store`. fn insert(\u0026amp;self, _key: \u0026amp;[u8]) -\u0026gt; String { \u0026#34;StaticKey\u0026#34;.to_string() } /// Get a key from the `Store`. fn get_key(\u0026amp;self, _id: \u0026amp;str) -\u0026gt; Option\u0026lt;Vec\u0026lt;u8\u0026gt;\u0026gt; { Some(self.0.to_vec()) } } fn main() { let mut config = libpasta::Config::default(); config.set_key_source(\u0026amp;STATIC_SOURCE); // Construct an HMAC instance and use this as the outer configuration let keyed_function = libpasta::primitives::Hmac::with_key_id(\u0026amp;digest::SHA256, \u0026#34;key\u0026#34;); config.set_keyed_hash(keyed_function); let hash = config.hash_password(\u0026#34;hunter2\u0026#34;.to_string()); println!(\u0026#34;Computed hash: {:?}\u0026#34;, hash); }"
},
{
"uri": "https://libpasta.github.io/other-languages/php/",
"title": "PHP",
"tags": [],
"description": "",
"content": "For PHP, SWIG generates a pasta.so extension, which can be installed in the system directory (for example, /etc/php/php.ini), and must be enabled. SWIG also generates a pasta.php module file which loads the extension and defines the API for libpasta.\n// In pasta_form.php \u0026lt;?php include(\u0026#34;pasta.php\u0026#34;); $password = $_POST[\u0026#39;password\u0026#39;]; $hash = pasta::hash_password(\u0026#34;hello123\u0026#34;); if (pasta::verify_password($hash, $password)) { echo \u0026#34;Correct password.\u0026#34;; } else { echo \u0026#34;Sorry, that is incorrect\u0026#34;; } ?\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;libpasta PHP example\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;form action=\u0026#34;pasta_form.php\u0026#34; method=\u0026#34;post\u0026#34;\u0026gt; \u0026lt;p\u0026gt;Please enter yor password (hint: hello123) \u0026lt;input type=\u0026#34;password\u0026#34; name=\u0026#34;password\u0026#34; /\u0026gt;\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;\u0026lt;input type=\u0026#34;submit\u0026#34; /\u0026gt;\u0026lt;/p\u0026gt; \u0026lt;/form\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt;"
},
{
"uri": "https://libpasta.github.io/advanced/migration/",
"title": "Password Migration",
"tags": [],
"description": "",
"content": "One of the core principles underlying libpasta is that it should be easy to use best practice password hashing algorithms. Unfortunately, many people are currently not using these algorithms, and furthermore, \u0026ldquo;best practice\u0026rdquo; seems to be very hard to pin down. To solve this, we include support for painless migration, which can even be enabled automatically.\nMigrating a password hash is a subtle problem. The whole point of password storage is that you cannot recover the password. To solve this, libpasta uses the onion approch.\nSuppose we have a password hash H = f(password, salt), and wish to migrate from using algorithm f to algorithm g. Clearly we cannot compute H' = g(password, salt) without first knowing the password.\nHence, we instead compute H' = g(f(password, salt), salt), applying the new hash function on top of the old one.\nIn libpasta, this is represented by a hash of the form:\n$!$argon2i$m=4096,t=3,p=1$$2y-mcf$cost=12$1hKt7q7c... Note we have both argon2i and 2y-mcf (bcrypt) in the hash value. This is a bcrypt hash, with cost 12, which has then been further hashed using Argon2i.\nOnce the user next successfully logs in, this double-hash can simply be updated once again to a standard, single hash.\nTo change hashing algorithms incurs a one-off cost to go through an re-hash all passwords. Migration tools are coming soon. For example, for Ruby on Rails, the following Rake script could be used for password migration:\nnamespace :pasta do desc \u0026#34;Updates all passwords to the default password algorithm\u0026#34; task migrate_passwords: :environment do User.all.each do |user| user.password_digest = Pasta::migrate_hash(user.password_digest) user.save end end end On each subsequent user login, there is an additional overhead incurred: first the cost of computing g(f(password)), which is at worst the cost of two long hashes, plus an additional computation of g(password). However, this migration step only need to happen once per customer, providing a seamless transition experience.\nOf course, there is the possibility that a user does not log in for such a long time that they end up having multiple layers h4(h3(h2(h1(password)))), which could potentially take a long time to migrate, and consume too much storage in the database. Note that the storage only grows linearly in the length of the parameters of h1...h4, since the salt/hash size is fixed. This additional time incurred for an infrequent user is a minor tradeoff for security and convenience.\n"
},
{
"uri": "https://libpasta.github.io/other-languages/python/",
"title": "Python",
"tags": [],
"description": "",
"content": "We are currently supporting the base libpasta functionality in python.\nThe library can be obtained by following the instruction in the repository. Or using pip for supported systems (currently 64-bit linux, most python versions).\nOnce obtained a simple example such as the following can be constructed:\nimport libpasta hash = libpasta.hash_password(\u0026#34;hello123\u0026#34;) password = libpasta.read_password(\u0026#34;Please enter the password (hint: hello123):\u0026#34;); if libpasta.verify_password(hash, password): print(\u0026#34;Correct password\u0026#34;) else: print(\u0026#34;Sorry, that is incorrect\u0026#34;)"
},
{
"uri": "https://libpasta.github.io/technical-details/randomness/",
"title": "Randomness Problems",
"tags": [],
"description": "",
"content": "One benefit of Rust is that it enforces strict error handling in applications. Rust has unwrap and expect methods which are generally used to mean \u0026ldquo;I have no idea how to recover from this particular error, please kill the program\u0026rdquo;.\nFor example, imagine some binary application which is used to count the lines of a file cargo run --bin wc some_file.txt it seems reasonable to panic if some_file.txt is not found, which would communicate this issue clearly.\nAbusing unwrap and expect leads to faulty software. If a password library panicked every time it receives a password hash which was too short (perhaps the database read was truncated for some reason) then it is going to cause significant issues down the road for the web application.\nIn libpasta, there are currently two main sources of failures: hash de/serialization failures, and failure to generate random values. Here we focus on the latter, the former should be covered by a well-defined serialization format and thorough testing/fuzzing.\nWhen calling libpasta::hash_password, the library will attempt to generate a random salt for hashing. If this fails, it is not clear that there is any meaningful strategy which can be performed. Returning this error to the developer significantly complicates the API, without a good chance they can do anything about it. Blocking until randomness is available is also a poor strategy. Hence we look to provide a reasonably fallback strategy.\nOn first use libpasta initializes a number of configuration options (see basic configuration). At this point, libpasta will also test out the default source of randomness (as configured by ring), to initialize a seed. This seed is used as the input to a PRNG, which can deterministically generate salts for new password hashes. If this seed is never recovered by an adversary, there is no problem, and all the salts are still pseudorandom. If, however, the current seed is compromised, all future salts are predictable. However it is still hopefully the case that salts will be per-user distinct which is the main property we wish to achieve.\nHence, instead of failing, here we provide an acceptable fallback mechanism which guarantees the system can continue operating even in unexpected circumstances.\n"
},
{
"uri": "https://libpasta.github.io/other-languages/ruby/",
"title": "Ruby",
"tags": [],
"description": "",
"content": "In the future Ruby will be supported through a Ruby gem. For now, SWIG generates a pasta.so extension which can be used directly by Ruby:\nrequire \u0026#39;./pasta.so\u0026#39; hash = Pasta::hash_password(\u0026#34;hello123\u0026#34;) password = Pasta::read_password(\u0026#34;Please enter the password (hint: hello123):\u0026#34;) if Pasta::verify_password(hash, password) puts \u0026#34;Correct password\u0026#34; else puts \u0026#34;Sorry, that is incorrect\u0026#34; end"
},
{
"uri": "https://libpasta.github.io/technical-details/phc-string-format/",
"title": "Serializing Hashes",
"tags": [],
"description": "",
"content": "We use the PHC string format, as defined here, to format password hashes produced by libpasta.\nThese take the following format:\n $\u0026lt;id\u0026gt;[$\u0026lt;param\u0026gt;=\u0026lt;value\u0026gt;(,\u0026lt;param\u0026gt;=\u0026lt;value\u0026gt;)*][$\u0026lt;salt\u0026gt;[$\u0026lt;hash\u0026gt;]] where:\n \u0026lt;id\u0026gt; is the symbolic name for the function \u0026lt;param\u0026gt; is a parameter name \u0026lt;value\u0026gt; is a parameter value \u0026lt;salt\u0026gt; is an encoding of the salt \u0026lt;hash\u0026gt; is an encoding of the hash output The string is then the concatenation, in that order, of:\n a $ sign; the function symbolic name; optionally, a $ sign followed by one or several parameters, each with a name=value format; the parameters are separated by commas; optionally, a $ sign followed by the (encoded) salt value; optionally, a $ sign followed by the (encoded) hash output (the hash output may be present only if the salt is present). "
},
{
"uri": "https://libpasta.github.io/technical-details/supported/",
"title": "Supported Algorithms",
"tags": [],
"description": "",
"content": " This page lists the hash formats currently supported by libpasta, and the algorithms available for use. For any missing formats/algorithms, please open an issue and/or submit a pull request.\nAlgorithms Currently, libpasta has support for:\n argon2 bcrypt HMAC PBKDF2 scrypt Formats The following hash-formats are supported automatically by libpasta:\n Name Format Description bcrypt legacy format $2[abxy]$\u0026lt;cost\u0026gt;$\u0026lt;salthash\u0026gt; salthash is a non-standard base64 encoding PHC format $\u0026lt;id\u0026gt;$\u0026lt;params map\u0026gt;$\u0026lt;salt\u0026gt;$\u0026lt;hash\u0026gt; Also referred to as modular crypt format libpasta specific ($!\u0026lt;PHC hash\u0026gt;)*$\u0026lt;PHC hash\u0026gt; nested MCF hash "
},
{
"uri": "https://libpasta.github.io/introduction/installation/",
"title": "Installation",
"tags": [],
"description": "",
"content": "libpasta is designed to be installed as a system library. Currently, this can be achieved by downloading the repository, compiling it, and moving the library to the system library, e.g /usr/lib.\ngit clone https://github.com/libpasta/libpasta/ cd libpasta # compiles the library make libpasta # installs the library to ${INSTALL_DIR} - defaults to /usr/lib make install For developing Rust applications, we recommend using it as usual through cargo.\nFor non-Rust applications, follow the above steps to install the library, and follow the instructions for bindings to other languages.\n"
},
{
"uri": "https://libpasta.github.io/advanced/tuning/",
"title": "Tuning & Parameter Selection",
"tags": [],
"description": "",
"content": "libpasta comes with a set of secure default algorithm and parameter choices. However, there is no single set of parameters which is suitable for all purposes and we provide tools to help with parameter selection.\nThese tools also have the benefit of working as a benchmarking platform for the target system; if the system performs significantly worse than the expected times, this could result in suboptimal, or even insecure, parameters selected.\nCurrently, running tune -h gives the following output:\n$ tune -h tune 0.0.1 Sam Scott libpasta tuning tool USAGE: tune [FLAGS] [OPTIONS] FLAGS: -h, --help Prints help information -p, --print Output the final result in the configuration file format -V, --version Prints version information -v, --verbose Print test information verbosely OPTIONS: -a, --algorithm \u0026lt;algorithm\u0026gt; Choose the algorithm to tune (default: argon2i) [values: argon2i, bcrypt, scrypt] -t, --target \u0026lt;target\u0026gt; Set the target number of verifications per second to support (defaut: 2) Running simple tune will benchmark various parameter choices (for the default options) until optimal values are found. Configuration options include the algorithm to target, and the default number of logins per second to be supported.\nFinally, the -p flag can be used to produce a libpasta-compatible configuration file.\n$ tune -a scrypt -p CPU speed: 2800 Predicted maximum parameter: 17, with time: 0.437s logN = 5, parallel = 1, read size = 8 ~\u0026gt; memory = 33 KiB 0.0001 s (estimated: 0.0001 s) logN = 6, parallel = 1, read size = 8 ~\u0026gt; memory = 65 KiB 0.0002 s (estimated: 0.0002 s) logN = 7, parallel = 1, read size = 8 ~\u0026gt; memory = 129 KiB 0.0004 s (estimated: 0.0004 s) ... logN = 16, parallel = 1, read size = 8 ~\u0026gt; memory = 65537 KiB 0.1791 s (estimated: 0.2186 s) logN = 17, parallel = 1, read size = 8 ~\u0026gt; memory = 131073 KiB 0.3581 s (estimated: 0.4372 s) logN = 18, parallel = 1, read size = 8 ~\u0026gt; memory = 262145 KiB 0.7151 s (estimated: 0.8743 s) Maximum amount of memory (capped at 2036080 KiB) to achieve \u0026lt; 0.50 s hash = 131088 KiB Recommended: SCrypt, N: 131072, r: 8, p: 1 Default: SCrypt, N: 16384, r: 8, p: 1 Algorithm in configuration format: --- default: Custom primitive: id: \u0026#34;scrypt-mcf\u0026#34; params: log_n: \u0026#34;17\u0026#34; r: \u0026#34;8\u0026#34; p: \u0026#34;1\u0026#34; There are a few interesting things to observe from the output. First of all, notice that the algorithm estimated maximum parameter choice to be 14, taking 0.055s, which is extremely close to the eventual value. This is a sense-check to ensure the system does not perform unexpectedly slow, which might indicate there is another process running which is consuming CPU time and skewing the benchmarks.\nWe left the target number of logins/second (the -t flag) at the default value of 2. This is the recommended amount for interactive logins, such as for websites. For offline applications, for example key derivation for disk encryption, a better value is 1 login every 3 seconds, so -t 0.33.\n"
},
{
"uri": "https://libpasta.github.io/introduction/password-hashing-theory/",
"title": "Password hashing theory",
"tags": [],
"description": "",
"content": " Why hash passwords? Let\u0026rsquo;s start with the most common use of passwords: user authentication.\nThe general setting is that an individual has a username and a password, e.g. username: alice and password: hunter2.\nWhen Alice first registers on a website, a new account is created, and the password is stored in the database, so that Alice can prove she is indeed Alice\nid | username | password | creation-date | ... ------------------------------------------------ 1 | alice | hunter2 | 2017-07-14 | ... However, if somebody gains access to this database with malicious intent - whether external hackers, or internal such as a database admin - Alice\u0026rsquo;s password is sitting in the open.\nThis is bad, since Alice is a typical user who likes to re-use the same password across multiple services. Unfortunately, service providers do not have the luxury of assuming all users have unique, high-entropy passwords.\nHence we want to apply a one-way function f to the password, so that nobody can reverse the function f(password) and work out the password, but given a password other-password it is easy to check whether f(password) == f(other-password).\nFrom the wikipedia page, we learn that SHA256 is a candidate one-way function, so we go ahead and use this as our hash function.\nNow, our database might look something like this:\nid | username | password | creation-date | ... -------------------------------------------------- 1 | alice | f52fbd32... | 2017-07-14 | ... This looks better, now the password isn\u0026rsquo;t revealed in the clear. However, this is actually not much better than the cleartext version.\nPlain cryptographic hash functions are not suitable for password hashing functions.\nNot SHA256, not SHA512, and no, not MD5.\nBrute force attacks In the previous example, we simply applied SHA256 to attempt to hide the password.\nThe reason for this is due to one of the fundamental requirements of password hashing algorithms: computing many outputs should be slow.\nAs in the previous example, suppose the attacker has access to the entire password database, with usernames and SHA256 hashes of passwords.\nThe attacker can take a list of common password and simply test every single value against the database. Looking at some commodity hardware, we see that (at the time of writing), $2,400 USD can get you a machine which computes 14,000,000,000,000 hashes per second.\nTo put that in perspective, that can compute every 7 character password made up of a-zA-Z0-9 in less than once second.\nThus we have the great dichotomy of password hashing:\nComputing one password hash should be fast, computing many should be slow\nPassword hashing algorithms To be resistant to a brute-force attack, password hashing algorithms are intentionally made to be slow. As a simple example of this, we have PBKDF2, which is effectively \u0026ldquo;take a cryptographic hash function, and repeat it N times\u0026rdquo;.\nPassword hashing algorithms allow you to choose parameters to slow down the hash function. For interactive logins (think: website login), choosing parameters such that login takes half a second is reasonable.\nIf it takes half a second to compute a single password hash, then guessing a 7 character password as before would take over 55 thousand years.\nHowever, in practice attackers will be using the list of common passwords we mentioned before. Even checking the top 10,000 most passwords will only take about an hour and a half.\nAre these password doomed to be recovered that easily?\nSalting password hashes Before, we saw that many password could be recovered in just an hour and a half. It was implicitly assumed that for any given password, the value stored in the database would be the same for any user. Suppose Alice and Charlie happen to share the same common password:\nid | username | password | creation-date | ... -------------------------------------------------- 1 | alice | cXmBfX44... | 2017-07-14 | ... 2 | bob | BlEi9jKX... | 2017-07-10 | ... 3 | charlie | cXmBfX44... | 2017-07-01 | ... Therefore, we typically add what is called a \u0026ldquo;salt\u0026rdquo; as an input to a password hash. This is a per-user unique value. So we get hash = f(password, salt).\nSince the salt is unique for each user, any brute force attack would need to be mounted on a per-user basis. This is a huge improvement when the attacker is simply interested in recovering as many passwords as possible, but is not necessarily interested in a specific user.\nKeyed hashes People familiar with the basics of cryptography might be wondering why we are not using encryption to protect the password hashes. Indeed, without the key, an encrypted hash is worthless to an attacker.\nSince we do not need decryption algorithms, we can use keyed hash functions such as HMAC instead. This has the same effect, without the key k it will be impossible to compute f_k(password, salt), and thus an attacker would not be able to check whether their password guess is correct.\nProperly protecting the key k is a difficult problem, and compromise of k renders it useless. One effective way is to store k in specialised hardware such as an HSM. However, there exist solutions (warning: PDF) which can help in making keyed solutions more accessible.\nAnother option is to involve a key in the storage mechanism to encrypt the password hash after hashing. While this has a number of drawbacks compared to using HMAC, one benefit is that it becomes possible to perform key rotation. In the event that the password storage is compromised, but not the encryption key, the key used to store passwords can be updated, rendering the leaked passwords useless.\nWe discuss how to use keys in libpasta in Keyed Hashes.\nMemory hard password hashes In recent times, such as in the password hashing competition, memory hard password hashing has been emphasised as an important part of the design criteria.\nThe main concept here is that it can be significantly cheaper to perform computation on custom hardware (e.g. ASICs), than on a general purpose CPU.\nBefore, we discussed the requirement that it should be fast to compute a single output, but slow to compute many. In order to make this as balanced as possible, we need to ensure that an adversary computing many hashes on custom hardware should not have an advantage over the innocent party using general-purpose hardware.\nAs a potential solution to this, memory-hard hashing functions have been proposed. Reading and writing to memory is an operation which is approximately equally expensive on custom hardware, and the cost to produce ASICs capable of handling more memory is significantly higher. Therefore, the advantage of these custom solutions is reduced.\nSummary Password hashing is essential to protect passwords from being leaked after a data breach. However, it is far from straightforward given the many considerations in play, such as: salting, security-parameters choices, key management, and memory-hardness.\nHence, we created libpasta to help accomodate the needs of the majority of use cases, providing an easy-to-use API which removes the necessity for the technical knowledge to choose appopriate algorithms and parameters.\n"
},
{
"uri": "https://libpasta.github.io/introduction/alternatives/",
"title": "Alternatives",
"tags": [],
"description": "",
"content": " There are currently a few options for password hashing. These vary from general crypto libraries, to specific password hashing libraries, to in-built helpers. The functionality, security, ease-of-use and compatibility of these varies, and we compare them to libpasta here.\nThe design of libpasta was inspired by libsodium (a cross-platform, cross- language crypto library), and passlib (a python-based password hashing library). libpasta is an effort to take the best features of these two libraries combined into one, and more.\nlibsodium libsodium is a well designed cryptography library, targeting security and ease-of-use. Much of the design of libpasta was inspired by libsodium.\nFurthermore, libsodium includes password hashing, so why choose libpasta over libsodium?\nPros Well-designed, mature library. Available for install on many operating systems, and with many bindings for other languages.\nCons No support for migrating from weak hashes \u0026ndash; one of the main needs for libpasta. While the coverage of supported languages is great, there are multiple bindings for each language, of varying quality.\nFurthermore, compare the difficulty of using libsodium:\n#define PASSWORD \u0026#34;Correct Horse Battery Staple\u0026#34; char hashed_password[crypto_pwhash_STRBYTES]; if (crypto_pwhash_str (hashed_password, PASSWORD, strlen(PASSWORD), crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE) != 0) { /* out of memory */ } if (crypto_pwhash_str_verify (hashed_password, PASSWORD, strlen(PASSWORD)) != 0) { /* wrong password */ } compared to the equivalent code in libpasta:\n#define PASSWORD \u0026#34;Correct Horse Battery Staple\u0026#34; char *hashed_password; hashed_password = hash_password(PASSWORD); if (verify_password(hashed_password, PASSWORD)) { /* wrong password */ } Summary libpasta is aiming to be the \u0026ldquo;libsodium for password hashing\u0026rdquo; \u0026ndash; a ubiquitous systems library with wide support. In its early development, libpasta is not at the same maturity level as libsodium. However, libpasta is specifically designed for password hashing, has a wider feature set, and a simpler API.\npasslib passlib is a password hashing library for Python 2 \u0026amp; 3. It has a wide feature set, and supports multiple platforms.\npasslib allows configuring a CryptContext object to specify a hashing \u0026ldquo;policy\u0026rdquo; (our words). That is, it supports whitelisting/blacklisting hashing algorithms, and even supports hash migration. However, this is only the full migration, not the partial migration libpasta additionally supports.\nPros Python library, easily supported across mutliple platforms. Good support for outdated algorithms, and ability to update hashes.\nCons Only for Python. Documentation is not particularly friendly for newbies, and seems to suggest PBKDF2 is the best algorithm. Scrypt is supported, but not recommended. Only supports the Argon2i variant.\nDjango password hashers (+) Easy-to-use defaults (+) Good alg support (+) Support full/wrapped migrations by hard coded classes (-) Only for Django (-) Uses PBKDF2 by default with 100000 iterations. (-) Requires defining new subclass to configure \u0026ndash; awkward config. https://docs.djangoproject.com/en/2.0/topics/auth/passwords/\nPHP password_hash As of version 5.5, PHP supports password hashing natively through password_hash.\n (+) Default bcrypt, supports Argon2i as well. (+) Easy-to-use defaults. (-) PHP only. Ruby on Rails - Bcrypt (+) Easy-to-use defaults. (-) Rails only (-) Default bcrypt, cost is just 10. "
},
{
"uri": "https://libpasta.github.io/blog/",
"title": "Blog",
"tags": [],
"description": "",
"content": " Posts "
},
{
"uri": "https://libpasta.github.io/blog/bindings/",
"title": "Rust for Cross-Language System Libraries",
"tags": [],
"description": "",
"content": " We have been building libpasta as a simple, usable solution to password hashing and migration. The goal for libpasta is to be a cross-platform, cross-language system library.\nlibpasta is written in Rust, exports a C-style API, and builds to a static/shared library. Most languages support calling external libraries through foreign function interfaces (FFIs), and the end result can be seen in the documentation where each language has access to the libpasta functionality.\nThis post is about how we use Rust + cbindgen + Swig to automate the process of creating bindings in each language which should feel like a natively-written library.\nThis does not necessarily apply to existing systems libraries which are rewritten in Rust, since bindings may already exist in multiple languages and the Rust library will have to export identically defined functions as expected by the library users.\nAlong the way, we cover some of the sharp edges you may encounter when using FFI.\nStep 1. From Rust to C Consider the most basic function in libpasta:\npub fn hash_password(password: \u0026amp;str) -\u0026gt; String { ... } which takes in a reference to a string and returns a new String.\nSuch a simple function should be easy to export as a C function, right? But a String is basically just a vector of bytes Vec\u0026lt;u8\u0026gt;, whereas a C string would be an array of chars terminated in a null byte \\0.\nLuckily, the std::ffi module contains a lot of the details necessary to make this conversion work. We can go from a pointer *const char to a borrowed \u0026amp;Cstr, and call to_str on that to (maybe) get a \u0026amp;str (it checks whether the input is indeed a legitimate UTF-8 string).\nSimilarly, given a Rust String, this can be converted to a CString and converted into a raw pointer of type *mut c_char.\nAll this information and much more can be found in the FFI omnibus, a fantastic resource for using Rust + FFI. Using all of this, it becomes easy enough to build the extern version of hash_password, perhaps ending up with something like1:\n#[no_mangle] pub extern fn hash_password(password: *const c_char) -\u0026gt; *mut c_char { let password = unsafe { assert!(!password.is_null()); CStr::from_ptr(password) }; let hash = libpasta::hash_password(password); CString::new(hash).unwrap().into_raw() } Until you read these lines from the Omnibus:\n Returning an allocated string via FFI is complicated for the same reason that returning an object is: the Rust allocator can be different from the allocator on the other side of the FFI boundary.\n \u0026hellip;\n Ownership of the string is transferred to the caller, but the caller must return the string to Rust in order to properly deallocate the memory.\n This is a huge pain. For something as simple as \u0026ldquo;input a string, return a string\u0026rdquo; we now require the caller to call free_string(s) on every s returned by this function.\nManually calling free on everything might be standard practice in C, but most other languages will find this cumbersome. Leaving this around feels like a particularly sharp edge for users to deal with, and does not mesh well with the ease-of-use goal for libpasta.\nWe will show how Swig solves this in step 3, but first, a quick look at how cbdingen makes using these extern definitions easier.\nStep 2. Static libs and using cbindgen Currently, we leave the libpasta crate as the pure-Rust crate, and define a new crate libpasta-capi to contain all of the extern functions we create in step 1.\nBy adding the lines:\n[lib] crate-type = [\u0026#34;cdylib\u0026#34;, \u0026#34;staticlib\u0026#34;] to our Cargo.toml file, cargo will now build shared/dynamic (e.g. *.so) and static (e.g. *.a) versions of the library. More about crate types in the book. The long-term goal is for libpasta.so, or windows-equivalent, to be installable from libpasta-capi as a shared library for re-use. In the shorter term, to help with testing, the static version is useful.\nNow any language which can call out to libraries can access these functions. For example, in C we just need to define a header file and link to the library. cbindgen is a Rust tool to help with this process. It can either be used as a CLI tool, or added to build.rs as part of the build process, and generates a C or C++ header file from any extern function definitions.\nRunning cargo build with cbindgen in our build.rs results in:\nchar *hash_password(const char *password); Automating the conversion of Rust extern functions to a C header file is a nice thing to have, resulting in one fewer place where changes need to be made when modifying the exported functions. cbindgen also has a bunch of nice features, and handles structs and enums well It also makes for a reasonably effective sense-check. For example, for a regular enum, cbindgen will just consider it an opaque struct, whereas using #[repr(C)] will produce an actual C enum definition.\nStep 3. Language bindings with SWIG SWIG is a tool for generating wrapper code for C/C++ code. It takes in a header definition file, and outputs language-specific interfaces.\nIt is difficult to convey adequately here just how much heavy lifting Swig is doing. But consider all the caveats from step 1 when going Rust \u0026lt;-\u0026gt; C, and imagine handling all of these for many languages automatically.\nAs opposed to simply running Swig on a header file, it is more common to use a special .i interface file. This file is used to help guide the behaviour of Swig, and define additional functionality.\nWith Swig, we can efficiently solve the annoying String deallocation problem from earlier! The line %newobject hash_password tells Swig that the return object from hash_password should be owned, and therefore needs to be cleaned up by the native code. Next, the annotation %typemap(newfree) char * \u0026quot;free_string($1);\u0026quot;;, tells Swig how to delete a char * - by calling free_string on that value.\nFor example, in the case of python, you get code like this (wrapper code is C++):\nresult = (char *)hash_password((char const *)arg1); resultobj = SWIG_FromCharPtr((const char *)result); if (alloc1 == SWIG_NEWOBJ) delete[] buf1; free_string(result); return resultobj; That is, the wrapper code calls hash_password, and attempts to create a native python string from the char* pointer. On a success, the original Rust string is deallocated using free_string.\nPutting it all together Suppose we now add the functionality to verify password hashes in libpasta:\npub fn verify_password(hash: \u0026amp;str, password: \u0026amp;str) -\u0026gt; bool { ... } First we write the libpasta-capi version:\n#[no_mangle] pub extern fn verify_password(hash: *const c_char, pw: *const c_char) -\u0026gt; bool { ... } Building with cargo automatically gives us the compiled libraries, and a header file including:\n#include \u0026lt;stdbool.h\u0026gt; bool verify_password(const char *hash, const char *password); Note that cbindgen has included stdbool.h for us, we might have missed that otherwise.\nAnd running Swig over the new header file will give us verify_password definitions in all our target languages.\n\u0026gt;\u0026gt;\u0026gt; h1 = libpasta.hash_password(\u0026#34;hunter2\u0026#34;) \u0026gt;\u0026gt;\u0026gt; libpasta.verify_password(h1, \u0026#34;hunter2\u0026#34;) True With very little work we have a Python function returning Python booleans, and not just an integer which we may need to check the value.\nTaking it further: Structs and functions Up to this point we are still dealing with very simple functions which requires little interaction with the Rust code itself. The setup is just \u0026ldquo;thing goes in, Rust does computation, thing comes out\u0026rdquo;. So the filler code we have is mostly just type conversions.\nHowever, libpasta supports configuration using the Config struct, which impls the same functions, for example:\nimpl Config { fn new() -\u0026gt; Self { ... } fn hash_password(\u0026amp;self, password: \u0026amp;str) -\u0026gt; String { ... } } After consulting with the FFI Omnibus again, we realise Config needs to be used as an opaque pointer. Any methods of Config need to be exposed as a new function (effectively turning config.hash_password(pw) into Config::hash_password(config, pw)). Following the same steps as before, we try to define the extern variant as:\n#[no_mangle] pub extern fn config_new() -\u0026gt; *mut Config { ... } #[no_mangle] pub extern fn config_hash_password(config: *const Config, pw: *const c_char) -\u0026gt; *mut c_char { ... } #[no_mangle] pub extern fn config_free(config: *mut Config) { .. } cbindgen will happily oblige to turn Config into a opaque pointer by defining\nstruct Config; and wrapping the other methods as usual.\nHowever, this is where things get a bit more difficult. We cannot use the %newobject trick in Swig from before, since we aren\u0026rsquo;t able to clone Config to anything meaningful in the target language. But we still don\u0026rsquo;t want to force the user to perform freeing manually.\nWe could follow the advice from the FFI Omnibus in each language to turn these into structs/classes/objects or whatever each language offers, but this defeats the purpose of using Swig.\nInstead, we create a new C++ class in our Swig interface file, which will be inlined in the wrapper code, (using namespacing to avoid naming clashes but Swig will flatten namespaces by default). Since Swig supports C++, these classes will be converted into the appropriate object in the target languages.\nnamespace libpasta { class Config { ffi::Config *self; public: Config() { self = config_new(); }; ~Config() { config_free(self); self = NULL; }; char *hash_password(const char *password) { return config_hash_password(self, password); }; }; } Now Swig will do the work to convert these to proper, native methods. Which can be used like:\n\u0026gt;\u0026gt;\u0026gt; import libpasta \u0026gt;\u0026gt;\u0026gt; cfg = libpasta.Config() \u0026gt;\u0026gt;\u0026gt; cfg \u0026lt;libpasta.Config; proxy of \u0026lt;Swig Object of type \u0026#39;libpasta::Config *\u0026#39; at 0x7fae3bb85b70\u0026gt; \u0026gt; \u0026gt;\u0026gt;\u0026gt; cfg.hash_password(\u0026#34;hunter2\u0026#34;) \u0026#39;$$scrypt$ln=14,r=8,p=1$6MFy2ynsD3eZcp8FCZcunw$zrdE1fOrCIZYFO0xHGopxBUnody4AZ4LQ640LkRXU9A\u0026#39; Which in my opinion is pretty cool.\nAfter creating these bindings, there is still the task of packaging each language binding in each of the unique packaging methodologies\u0026hellip; But that\u0026rsquo;s an orthogonal problem which exists in either case.\nWhat if This is a pretty effective setup. We can write our Rust code as idiomatic as we want, write a few standard extern functions to access the main methods, and Swig mostly does the rest.\nHowever, the whole Rust -\u0026gt; C -\u0026gt; C++ -\u0026gt; Swig process is really one, if not two, hops too many. The C++ classes we are exposing are really the same Rust structs we would like to expose. It would be interesting to know whether wrapper C++ code could be written for Rust, which would effectively do the same as cbindgen.\nEven better would be perhaps procedural macros for Rust structs and functions which automatically derives these wrapper functions and builds the corresponding header files. It would be interesting to know the potential pitfalls of this approach.\nA few closing remarks Some languages have projects dedicated to interacting with Rust. E.g. ruru for Ruby \u0026lt;-\u0026gt; Rust. These potentially perform better, create better bindings, or have more features. I haven\u0026rsquo;t investigated yet and would be interested to know. In the future individual bindings could be improved this way. I haven\u0026rsquo;t yet benchmarked the overhead of all of this. However, since password hashing is intentionally slow (0.1-0.5s for example), this overhead should hopefully be a negligible amount. But for other libraries this might not be acceptable. Are there any obvious Rust patterns which are going to be a nightmare to wrap in C++? I haven\u0026rsquo;t yet tried to wrap error handling yet, but Swig has support for this. Also, cbindgen will happily convert a sum type/tagged union enum into a similar C++ struct using union, but Swig doesn\u0026rsquo;t yet support those, so they have to be handled a bit more manually. For long-term projects, it\u0026rsquo;s less likely that the API will be changing drastically, potentially reducing the value in doing any of the above. But its still useful (in my opinion) for the initial work. Thanks for reading! Happy to respond to any comments on the reddit thread, or reach out to me on twitter.\n This does have the unfortunate unwrap, which panics in case there is a \\0 byte in the string, which is permitted in Rust Strings. In the case of libpasta, everything is usually base64 encoded so should not happen.\n[return] "
},
{
"uri": "https://libpasta.github.io/blog/release/",
"title": "Announcing libpasta",
"tags": [],
"description": "",
"content": " Today we are announcing the alpha release of libpasta!\nlibpasta is intended to be a cross-language, cross-platform, easy-to-use password hashing library for developers. In particular, libpasta offers a simple API, which uses sane defaults, offering a relatively high security level with zero configuration or parameter choice for the developer. Storing/verifying a password is as simple as libpasta.hash_password(pw) and libpasta.verify_password(hash, pw).\nFurthermore, libpasta is built to handle migrating from old hashes, finally allowing developers to move away from old, outdated algorithms and parameters. Once libpasta is in place, it will happily update to any new algorithm or parameter choices.\nOur vision for libpasta, is to be available across many platforms, offering accessible password storage functionality to all applications. The core of libpasta is written in Rust, and we have already written a number of bindings for different languages.\nTo find out more, dive into some of the menu items on the left covering more about what is libpasta, password hashing theory, or getting started with libpasta.\nCurrent status libpasta is still in its early stages. The main functionality is written in Rust, with support for other languages following close behind. However, the core code needs to be audited/optimised.\nWe are currently looking for testing and feedback on the library.\nRoadmap Implement more hashing algorithms (for migration compatibility). Support for more platforms - OSX, 32-bit Linux, Windows Support for more languages - Ruby, JavaScript. More tools! We have built a basic tuning tool in Rust to generate optimal parameter sets, and can expand this out. Who we are So far, libpasta is being developed by Sam Scott as part of a NSF-funded project at Cornell Tech, in collaboration with Tom Ristenpart and Ari Juels. We are actively looking for new contributors, with the possibility of offering part and full-time positions to continue the work.\n"
},
{
"uri": "https://libpasta.github.io/categories/",
"title": "Categories",
"tags": [],
"description": "",
"content": ""
},
{
"uri": "https://libpasta.github.io/tags/",
"title": "Tags",
"tags": [],
"description": "",
"content": ""
},
{
"uri": "https://libpasta.github.io/",
"title": "libpasta",
"tags": [],
"description": "",
"content": ""
}]