├── go.mod ├── go.sum ├── example_test.go ├── LICENSE ├── README ├── yescrypt_wrapper.go ├── yescrypt_test.go └── yescrypt.go /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/openwall/yescrypt-go 2 | 3 | go 1.22.4 4 | 5 | require golang.org/x/crypto v0.25.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= 2 | golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= 3 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Copyright 2024 Solar Designer. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // yescrypt support sponsored by Sandfly Security https://sandflysecurity.com - 7 | // Agentless Security for Linux 8 | 9 | package yescrypt_test 10 | 11 | import ( 12 | "encoding/base64" 13 | "fmt" 14 | "log" 15 | 16 | "github.com/openwall/yescrypt-go" 17 | ) 18 | 19 | func Example() { 20 | // DO NOT use this salt value; generate your own random salt. 8 bytes is 21 | // a good length. 22 | salt := []byte{0xc8, 0x28, 0xf2, 0x58, 0xa7, 0x6a, 0xad, 0x7b} 23 | 24 | dk, err := yescrypt.ScryptKey([]byte("some password"), salt, 1<<15, 8, 1, 32) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | fmt.Println(base64.StdEncoding.EncodeToString(dk)) 29 | hash, err := yescrypt.Hash([]byte("openwall"), []byte("$y$j9T$AAt9R641xPvCI9nXw1HHW/")) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | fmt.Println(string(hash)) 34 | hash, err = yescrypt.Hash([]byte("pleaseletmein"), []byte("$y$j9T$e8R9q85ZuzUkArEUurdtS.$esON.7y6H.u3UCPVCpbRFueRpAut2n2cMf1EhpjbuiC")) 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | fmt.Println(string(hash)) 39 | // Output: lGnMz8io0AUkfzn6Pls1qX20Vs7PGN6sbYQ2TQgY12M= 40 | // $y$j9T$AAt9R641xPvCI9nXw1HHW/$cuQRBMN3N/f8IcmVN.4YrZ1bHMOiLOoz9/XQMKV/v0A 41 | // $y$j9T$e8R9q85ZuzUkArEUurdtS.$esON.7y6H.u3UCPVCpbRFueRpAut2n2cMf1EhpjbuiC 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2020 The Go Authors. All rights reserved. 2 | Copyright (c) 2024 Solar Designer. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Go implementation of scrypt and yescrypt key derivation and password hashing 2 | functions, which have their homepages at: 3 | https://www.tarsnap.com/scrypt.html 4 | https://www.openwall.com/yescrypt/ 5 | 6 | This Go implementation of scrypt was created in 2012 by Dmitry Chestnykh, who 7 | has since contributed it to the official Go x/crypto repository where it's now 8 | maintained by the Go authors. This tree is based on Dmitry's with all x/crypto 9 | changes as of mid-2024 added. The implementation of yescrypt was added in 2024 10 | by Solar Designer, sponsored by Sandfly Security https://sandflysecurity.com - 11 | Agentless Security for Linux. 12 | 13 | INSTALLATION 14 | 15 | $ go get github.com/openwall/yescrypt-go 16 | 17 | PACKAGE 18 | import "github.com/openwall/yescrypt-go" 19 | 20 | Package yescrypt implements the scrypt key derivation function as defined 21 | in Colin Percival's paper "Stronger Key Derivation via Sequential 22 | Memory-Hard Functions", as well as Solar Designer's yescrypt. 23 | 24 | FUNCTIONS 25 | 26 | func ScryptKey(password, salt []byte, N, r, p, keyLen int) ([]byte, error) 27 | 28 | ScryptKey implements classic scrypt (not yescrypt). It is compatible with 29 | the x/crypto scrypt module's Key. 30 | 31 | It derives a key from the password, salt and cost parameters, returning a 32 | byte slice of length keyLen that can be used as cryptographic key. 33 | 34 | N is a CPU/memory cost parameter, must be a power of two greater than 1. 35 | r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the 36 | limits, the function returns a nil byte slice and an error. 37 | 38 | For example, you can get a derived key for e.g. AES-256 (which needs a 39 | 32-byte key) by doing: 40 | 41 | dk, err := yescrypt.ScryptKey([]byte("some password"), salt, 32768, 8, 1, 32) 42 | 43 | The recommended parameters for interactive logins as of 2017 are N=32768, r=8 44 | and p=1. The parameters N, r, and p should be increased as memory latency and 45 | CPU parallelism increases; consider setting N to the highest power of 2 you 46 | can derive within 100 milliseconds. Remember to get a good random salt. 47 | 48 | func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) 49 | 50 | Key is similar to ScryptKey, but computes native yescrypt assuming 51 | reference yescrypt's current default flags (as of yescrypt 1.1.0), p=1 52 | (which it currently requires), t=0, and no ROM. Example usage: 53 | 54 | dk, err := yescrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) 55 | 56 | The set of parameters accepted by Key will likely change in future versions 57 | of this Go module to support more yescrypt functionality. 58 | 59 | func Hash(password, setting []byte) ([]byte, error) 60 | 61 | Computes yescrypt hash encoding given the password and existing yescrypt 62 | setting or full hash encoding. The salt and other parameters are decoded 63 | from setting. Currently supports (only a little more than) the subset of 64 | yescrypt parameters that libxcrypt can generate (as of libxcrypt 4.4.36). 65 | 66 | KEYWORDS 67 | 68 | go, golang, scrypt, yescrypt, kdf, hash, password 69 | -------------------------------------------------------------------------------- /yescrypt_wrapper.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Solar Designer. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Alternatively, this specific source file is also available under more 6 | // relaxed terms (0-clause BSD license): 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted. 9 | 10 | // yescrypt support sponsored by Sandfly Security https://sandflysecurity.com - 11 | // Agentless Security for Linux 12 | 13 | package yescrypt 14 | 15 | import ( 16 | "bytes" 17 | "errors" 18 | ) 19 | 20 | const itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 21 | 22 | var atoi64Partial = [...]byte{ 23 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 24 | 64, 64, 64, 64, 64, 64, 64, 25 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26 | 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 27 | 64, 64, 64, 64, 64, 64, 28 | 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 29 | 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 30 | } 31 | 32 | func atoi64(c byte) int { 33 | if c >= '.' && c <= 'z' { 34 | return int(atoi64Partial[c-'.']) 35 | } 36 | return 64 37 | } 38 | 39 | func encode64(src []byte) []byte { 40 | dst := make([]byte, 0, (len(src)*8+5)/6) 41 | for i := 0; i < len(src); { 42 | value, bits := uint32(0), 0 43 | for ; bits < 24 && i < len(src); bits += 8 { 44 | value |= uint32(src[i]) << bits 45 | i++ 46 | } 47 | for ; bits > 0; bits -= 6 { 48 | dst = append(dst, itoa64[value&0x3f]) 49 | value >>= 6 50 | } 51 | } 52 | return dst 53 | } 54 | 55 | func decode64(src []byte) []byte { 56 | dst := make([]byte, 0, len(src)*3/4) 57 | for i := 0; i < len(src); { 58 | value, bits := uint32(0), uint32(0) 59 | for ; bits < 24 && i < len(src); bits += 6 { 60 | c := atoi64(src[i]) 61 | if c > 63 { 62 | return nil 63 | } 64 | i++ 65 | value |= uint32(c) << bits 66 | } 67 | if bits < 12 { // Must have at least one full byte 68 | return nil 69 | } 70 | for ; bits >= 8; bits -= 8 { 71 | dst = append(dst, byte(value)) 72 | value >>= 8 73 | } 74 | if value != 0 { // May have 2 or 4 bits left, which must be 0 75 | return nil 76 | } 77 | } 78 | return dst 79 | } 80 | 81 | // Computes yescrypt hash encoding given the password and existing yescrypt 82 | // setting or full hash encoding. The salt and other parameters are decoded 83 | // from setting. Currently supports (only a little more than) the subset of 84 | // yescrypt parameters that libxcrypt can generate (as of libxcrypt 4.4.36). 85 | func Hash(password, setting []byte) ([]byte, error) { 86 | if len(setting) < 7 || string(setting[:4]) != "$y$j" || setting[6] != '$' { 87 | return nil, errors.New("yescrypt: unsupported parameters") 88 | } 89 | // Proper yescrypt uses variable-length integers 90 | // We take a shortcut approach that works in a more limited range 91 | Nlog2 := atoi64(setting[4]) + 1 92 | if Nlog2 < 10 || Nlog2 > 18 { 93 | return nil, errors.New("yescrypt: N out of supported range") 94 | } 95 | r := atoi64(setting[5]) + 1 96 | if r < 1 || r > 32 { 97 | return nil, errors.New("yescrypt: r out of supported range") 98 | } 99 | 100 | saltEnd := bytes.LastIndexByte(setting, '$') 101 | if saltEnd < 7 { 102 | saltEnd = len(setting) 103 | } 104 | salt := decode64(setting[7:saltEnd]) 105 | if salt == nil { 106 | return nil, errors.New("yescrypt: bad salt encoding") 107 | } 108 | 109 | key, err := Key(password, salt, 1< 217 | #include 218 | 219 | int main(void) 220 | { 221 | for (int count = 1; count <= 11; count++) { 222 | const char *setting = crypt_gensalt("$y$", count, NULL, 0); 223 | char pw[8]; 224 | snprintf(pw, sizeof(pw), "test%d", count); 225 | printf("\t{\"%s\", \"%s\"},\n", pw, crypt(pw, setting)); 226 | } 227 | for (int saltlen = 0; saltlen <= 24; saltlen++) { 228 | char pw[16], setting[32]; 229 | snprintf(pw, sizeof(pw), "salt length %d", saltlen); 230 | snprintf(setting, sizeof(setting), "$y$j7.$%.*s", saltlen, "////////////////////////"); 231 | printf("\t{\"%s\", \"%s\"},\n", pw, crypt(pw, setting) ?: setting); 232 | } 233 | return 0; 234 | } 235 | */ 236 | 237 | var hashes = []testVectorHash{ 238 | {"test1", "$y$j75$z7ztFz2FayrKI79/jEwlL.$u5x/j193MQ09wbFaRGYr0AH/A/jh3kunjuhYRVRNkmC"}, 239 | {"test2", "$y$j85$uFLpki6/G99e8OAxVooij1$64Rji3LKk1v85LYVULHKh2YKeKoDu0ADrGt4l1JhQy8"}, 240 | {"test3", "$y$j7T$aoovSEloTaFiZVMrFisfy.$wLTAPbITTB/XIpAGwcX0xxRCFEcDgPWpXTsij0SEbC5"}, 241 | {"test4", "$y$j8T$P9xODwGnzlle5VHuP1/qA1$bAd4BXv1GBqNQZFzR0Ey42/w0/DFmnFkX1fRpjalAO2"}, 242 | {"test5", "$y$j9T$fqIAg4Vpv9o1MKgWMnyax.$BxkUx27fLJlPOfyIfNEBPzjrDQ95LXKgN5OJii3GL7."}, 243 | {"test6", "$y$jAT$70Rw91iJgO8Uzi3CLWfOo1$aYky8YP.XurVMdZfcXHY1do2RZ7Caav5iliKEkmJjhD"}, 244 | {"test7", "$y$jBT$/YBmADVZsSMw3xfv8M76X0$14s2oH3zHEKh44d5eRVxmDvF8jgM/8SXd8mI4NBQIS1"}, 245 | /* 246 | {"test8", "$y$jCT$JXJjOzzWl5vilbjjonN5N1$.HyIln8Y5//hXrEaSMIFPSHBAE24eR392XzBtFELSv9"}, 247 | {"test9", "$y$jDT$pPCKQ.Jzpv90Nh7H.ioA9/$6fSLU.2dsGXHY1DZuRncQtItRzZNx9oClKgMpSEkyW0"}, 248 | {"test10", "$y$jET$YA8uEtDHnx9Sv9OvDcwv81$zfxVIsTgxs6v/qL.nTBEE.o9du75wuSHnF5Sai6K.s7"}, 249 | {"test11", "$y$jFT$c1pwXe.GpcUUeOK7BV6yX1$lys4J0.caCkYP6ZpfUj.2zuJAiTpMFj0O9HhN59/QI."}, 250 | */ 251 | {"salt length 0", "$y$j7.$$cmp7v9bzgyAhctAaiyqG56MBYN2IYzfI5LvybJCKacD"}, 252 | {"salt length 1", "$y$j7.$/"}, 253 | {"salt length 2", "$y$j7.$//$DcruwIS63Fs/rFjEN0XX6h83bZyXgBTDICvINmSWVp5"}, 254 | {"salt length 3", "$y$j7.$///$uo0SD4Xn0Bn1leZVH50teLu3Rje5GAIA.BKYA/jL3/C"}, 255 | {"salt length 4", "$y$j7.$////$WXGIKO.4sthsRPnpY0/.OhyrlEkLcS1pymEGTbJA/l."}, 256 | {"salt length 5", "$y$j7.$/////"}, 257 | {"salt length 6", "$y$j7.$//////$9/wDzXoL4.VS3Ztb.NPiOu4wTpTBKrnJTxBwH1fK70A"}, 258 | {"salt length 7", "$y$j7.$///////$iFpkxOqqnskGorbt2d.daPYT2vUWCRsisu0jr4sNF1."}, 259 | {"salt length 8", "$y$j7.$////////$caDf7LpLxRuDzYqMUDha1Nvm9zX2M89hTuCi.33hpMA"}, 260 | {"salt length 9", "$y$j7.$/////////"}, 261 | {"salt length 10", "$y$j7.$//////////$w8.ijckeAcw8QTQFtNDzf6GAbpM0GS1tPF9.moe8DA6"}, 262 | {"salt length 11", "$y$j7.$///////////$aNlOwAA3WuQ2GScDBr/fTD34oO0ZN/BksJ8d6ilH4O8"}, 263 | {"salt length 12", "$y$j7.$////////////$9YMdFtGt/uJi6XsLbYVhRfnneKsMgoos2r.7fZ8Xn.."}, 264 | {"salt length 13", "$y$j7.$/////////////"}, 265 | {"salt length 14", "$y$j7.$//////////////$fPBNb956TRLinNI/LHoThcqdVO5gIGIg/nRpmyzB/T/"}, 266 | {"salt length 15", "$y$j7.$///////////////$lzaOauYlT250iKS8qtIlo8Ail.PbSHjKSjRpPsEqcI6"}, 267 | {"salt length 16", "$y$j7.$////////////////$DlYtorMMW/M1IdFxGPdfFS.STo61kYy/eHnOanwVvrC"}, 268 | {"salt length 17", "$y$j7.$/////////////////"}, 269 | {"salt length 18", "$y$j7.$//////////////////$3P/0DYS.t.P2VC4rnF9kWURChONU4ehShDJyGUIoYZ9"}, 270 | {"salt length 19", "$y$j7.$///////////////////$.M.DTam6fr/7j36F7Mo0g3QGSYAD7PbZkwe8X9bJyd8"}, 271 | {"salt length 20", "$y$j7.$////////////////////$dHX43Z/x85XNKoOu4UDromlyoPcD9isScOP8ZeW6l27"}, 272 | {"salt length 21", "$y$j7.$/////////////////////"}, 273 | {"salt length 22", "$y$j7.$//////////////////////$XXf4WJAUsQCV6TUulO3H/f3OWOuK8j8FX9ZtJluydw4"}, 274 | {"salt length 23", "$y$j7.$///////////////////////$FOmK9/DdyesVtGrimp4GNqRPMQ5V6Z8/wfRPWZ.XhjA"}, 275 | {"salt length 24", "$y$j7.$////////////////////////$xW7NvvbWPmxoFVWCDe.WNwrrSfuN/iVvy/05.lD/MO9"}, 276 | // More expected errors 277 | {"", ""}, 278 | {"", "$y$.7.$$"}, 279 | {"", "$y$j..$$"}, 280 | } 281 | 282 | func TestHash(t *testing.T) { 283 | for i, v := range hashes { 284 | cut := len(v.hash) 285 | if cut > 29 && (i&1) != 0 { 286 | cut = 29 + i/2 287 | } 288 | hash, err := Hash([]byte(v.password), []byte(v.hash)[:cut]) 289 | if len(hash) < 51 { 290 | if err == nil { 291 | t.Errorf("%d: expected error, got %s, nil", i, hash) 292 | } 293 | continue 294 | } 295 | if err != nil { 296 | t.Errorf("Hash %d: got unexpected error: %s", i, err) 297 | } 298 | if string(hash) != v.hash { 299 | t.Errorf("Hash %d: expected %s, got %s", i, v.hash, hash) 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /yescrypt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2020 The Go Authors. All rights reserved. 2 | // Copyright 2024 Solar Designer. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package yescrypt implements the scrypt key derivation function as defined in 7 | // Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard 8 | // Functions", as well as Solar Designer's yescrypt. 9 | 10 | // yescrypt support sponsored by Sandfly Security https://sandflysecurity.com - 11 | // Agentless Security for Linux 12 | 13 | package yescrypt 14 | 15 | import ( 16 | "crypto/hmac" 17 | "crypto/sha256" 18 | "encoding/binary" 19 | "errors" 20 | "math/bits" 21 | 22 | "golang.org/x/crypto/pbkdf2" 23 | ) 24 | 25 | const maxInt = int(^uint(0) >> 1) 26 | 27 | // blockCopy copies n numbers from src into dst. 28 | func blockCopy(dst, src []uint64, n int) { 29 | copy(dst, src[:n]) 30 | } 31 | 32 | // blockXOR XORs numbers from dst with n numbers from src. 33 | func blockXOR(dst, src []uint64, n int) { 34 | for i, v := range src[:n] { 35 | dst[i] ^= v 36 | } 37 | } 38 | 39 | // salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in, 40 | // and puts the result into both tmp and out. 41 | func salsaXOR(tmp *[8]uint64, in, out []uint64, rounds int) { 42 | d0 := tmp[0] ^ in[0] 43 | d1 := tmp[1] ^ in[1] 44 | d2 := tmp[2] ^ in[2] 45 | d3 := tmp[3] ^ in[3] 46 | d4 := tmp[4] ^ in[4] 47 | d5 := tmp[5] ^ in[5] 48 | d6 := tmp[6] ^ in[6] 49 | d7 := tmp[7] ^ in[7] 50 | 51 | x0, x1 := uint32(d0), uint32(d6>>32) 52 | x2, x3 := uint32(d5), uint32(d3>>32) 53 | x4, x5 := uint32(d2), uint32(d0>>32) 54 | x6, x7 := uint32(d7), uint32(d5>>32) 55 | x8, x9 := uint32(d4), uint32(d2>>32) 56 | x10, x11 := uint32(d1), uint32(d7>>32) 57 | x12, x13 := uint32(d6), uint32(d4>>32) 58 | x14, x15 := uint32(d3), uint32(d1>>32) 59 | 60 | for i := 0; i < rounds; i += 2 { 61 | x4 ^= bits.RotateLeft32(x0+x12, 7) 62 | x8 ^= bits.RotateLeft32(x4+x0, 9) 63 | x12 ^= bits.RotateLeft32(x8+x4, 13) 64 | x0 ^= bits.RotateLeft32(x12+x8, 18) 65 | 66 | x9 ^= bits.RotateLeft32(x5+x1, 7) 67 | x13 ^= bits.RotateLeft32(x9+x5, 9) 68 | x1 ^= bits.RotateLeft32(x13+x9, 13) 69 | x5 ^= bits.RotateLeft32(x1+x13, 18) 70 | 71 | x14 ^= bits.RotateLeft32(x10+x6, 7) 72 | x2 ^= bits.RotateLeft32(x14+x10, 9) 73 | x6 ^= bits.RotateLeft32(x2+x14, 13) 74 | x10 ^= bits.RotateLeft32(x6+x2, 18) 75 | 76 | x3 ^= bits.RotateLeft32(x15+x11, 7) 77 | x7 ^= bits.RotateLeft32(x3+x15, 9) 78 | x11 ^= bits.RotateLeft32(x7+x3, 13) 79 | x15 ^= bits.RotateLeft32(x11+x7, 18) 80 | 81 | x1 ^= bits.RotateLeft32(x0+x3, 7) 82 | x2 ^= bits.RotateLeft32(x1+x0, 9) 83 | x3 ^= bits.RotateLeft32(x2+x1, 13) 84 | x0 ^= bits.RotateLeft32(x3+x2, 18) 85 | 86 | x6 ^= bits.RotateLeft32(x5+x4, 7) 87 | x7 ^= bits.RotateLeft32(x6+x5, 9) 88 | x4 ^= bits.RotateLeft32(x7+x6, 13) 89 | x5 ^= bits.RotateLeft32(x4+x7, 18) 90 | 91 | x11 ^= bits.RotateLeft32(x10+x9, 7) 92 | x8 ^= bits.RotateLeft32(x11+x10, 9) 93 | x9 ^= bits.RotateLeft32(x8+x11, 13) 94 | x10 ^= bits.RotateLeft32(x9+x8, 18) 95 | 96 | x12 ^= bits.RotateLeft32(x15+x14, 7) 97 | x13 ^= bits.RotateLeft32(x12+x15, 9) 98 | x14 ^= bits.RotateLeft32(x13+x12, 13) 99 | x15 ^= bits.RotateLeft32(x14+x13, 18) 100 | } 101 | 102 | d0 = uint64(uint32(d0)+x0) | uint64(uint32(d0>>32)+x5)<<32 103 | d1 = uint64(uint32(d1)+x10) | uint64(uint32(d1>>32)+x15)<<32 104 | d2 = uint64(uint32(d2)+x4) | uint64(uint32(d2>>32)+x9)<<32 105 | d3 = uint64(uint32(d3)+x14) | uint64(uint32(d3>>32)+x3)<<32 106 | d4 = uint64(uint32(d4)+x8) | uint64(uint32(d4>>32)+x13)<<32 107 | d5 = uint64(uint32(d5)+x2) | uint64(uint32(d5>>32)+x7)<<32 108 | d6 = uint64(uint32(d6)+x12) | uint64(uint32(d6>>32)+x1)<<32 109 | d7 = uint64(uint32(d7)+x6) | uint64(uint32(d7>>32)+x11)<<32 110 | 111 | out[0], tmp[0] = d0, d0 112 | out[1], tmp[1] = d1, d1 113 | out[2], tmp[2] = d2, d2 114 | out[3], tmp[3] = d3, d3 115 | out[4], tmp[4] = d4, d4 116 | out[5], tmp[5] = d5, d5 117 | out[6], tmp[6] = d6, d6 118 | out[7], tmp[7] = d7, d7 119 | } 120 | 121 | func blockMix(tmp *[8]uint64, in, out []uint64, r int) { 122 | blockCopy(tmp[:], in[(2*r-1)*8:], 8) 123 | for i := 0; i < 2*r; i += 2 { 124 | salsaXOR(tmp, in[i*8:], out[i*4:], 8) 125 | salsaXOR(tmp, in[i*8+8:], out[i*4+r*8:], 8) 126 | } 127 | } 128 | 129 | // These were tunable at design time, but they must meet certain constraints 130 | const ( 131 | PWXsimple = 2 132 | PWXgather = 4 133 | PWXrounds = 6 134 | Swidth = 8 135 | ) 136 | 137 | // Derived values. These were never tunable on their own. 138 | const ( 139 | PWXbytes = PWXgather * PWXsimple * 8 140 | PWXwords = PWXbytes / 8 141 | Sbytes = 3 * (1 << Swidth) * PWXsimple * 8 142 | Swords = Sbytes / 8 143 | Smask = (((1 << Swidth) - 1) * PWXsimple * 8) 144 | ) 145 | 146 | type pwxformCtx struct { 147 | S0, S1, S2 []uint64 148 | w uint32 149 | } 150 | 151 | func pwxform(X *[PWXwords]uint64, ctx *pwxformCtx) { 152 | S0, S1, S2, w := ctx.S0, ctx.S1, ctx.S2, ctx.w 153 | 154 | for i := 0; i < PWXrounds; i++ { 155 | for j := 0; j < PWXgather; j++ { 156 | // Unrolled inner loop for PWXsimple=2 157 | x := X[j*PWXsimple] 158 | xl := uint32(x) 159 | xh := uint32(x >> 32) 160 | x = uint64(xh) * uint64(xl) 161 | xl = (xl & Smask) / 8 162 | xh = (xh & Smask) / 8 163 | x = (x + S0[xl]) ^ S1[xh] 164 | X[j*PWXsimple] = x 165 | y := X[j*PWXsimple+1] 166 | y = ((y>>32)*uint64(uint32(y)) + S0[xl+1]) ^ S1[xh+1] 167 | X[j*PWXsimple+1] = y 168 | if i != 0 && i != PWXrounds-1 { 169 | S2[w] = x 170 | S2[w+1] = y 171 | w += 2 172 | } 173 | } 174 | } 175 | 176 | ctx.S0, ctx.S1, ctx.S2 = S2, S0, S1 177 | ctx.w = w & ((1< 1 { 228 | j := int(wrap(integer(x, r), uint32(i))) 229 | blockXOR(x, v[j*R:], R) 230 | } 231 | blockMixPwxform(&tmp, x, r, ctx) 232 | } 233 | for i := 0; i < Nloop; i++ { 234 | j := int(integer(x, r) & uint32(N-1)) 235 | blockXOR(x, v[j*R:], R) 236 | blockCopy(v[j*R:], x, R) 237 | blockMixPwxform(&tmp, x, r, ctx) 238 | } 239 | } else { 240 | for i := 0; i < N; i += 2 { 241 | blockCopy(v[i*R:], x, R) 242 | blockMix(&tmp, x, y, r) 243 | 244 | blockCopy(v[(i+1)*R:], y, R) 245 | blockMix(&tmp, y, x, r) 246 | } 247 | for i := 0; i < Nloop; i += 2 { 248 | j := int(integer(x, r) & uint32(N-1)) 249 | blockXOR(x, v[j*R:], R) 250 | blockMix(&tmp, x, y, r) 251 | 252 | j = int(integer(y, r) & uint32(N-1)) 253 | blockXOR(y, v[j*R:], R) 254 | blockMix(&tmp, y, x, r) 255 | } 256 | } 257 | j = 0 258 | for _, v := range x[:R] { 259 | binary.LittleEndian.PutUint32(b[(j & ^63)|((j*5)&63):], uint32(v)) 260 | j += 4 261 | binary.LittleEndian.PutUint32(b[(j & ^63)|((j*5)&63):], uint32(v>>32)) 262 | j += 4 263 | } 264 | } 265 | 266 | func smixYescrypt(b []byte, r, N int, v, xy []uint64, passwordSha256 []byte) { 267 | var ctx pwxformCtx 268 | var S [Swords]uint64 269 | smix(b, 1, Sbytes/128, 0, S[:], xy, nil) 270 | ctx.S2 = S[:] 271 | ctx.S1 = S[(1< 1 and a power of 2") 282 | } 283 | if r <= 0 { 284 | return nil, errors.New("(ye)scrypt: r must be > 0") 285 | } 286 | if isYescrypt && p != 1 { 287 | return nil, errors.New("yescrypt: p must be 1") 288 | } 289 | if p <= 0 { 290 | return nil, errors.New("scrypt: p must be > 0") 291 | } 292 | if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r { 293 | return nil, errors.New("(ye)scrypt: parameters are too large") 294 | } 295 | 296 | ppassword := &password 297 | pass := 1 298 | prehash := []byte("yescrypt-prehash") 299 | 300 | v := make([]uint64, 16*N*r) 301 | var xy []uint64 302 | var key []byte 303 | 304 | if isYescrypt { 305 | xy = make([]uint64, 16*max(r, 2)) 306 | if N/p >= 0x100 && N/p*r >= 0x20000 { 307 | pass = 0 308 | N >>= 6 309 | } 310 | } else { 311 | xy = make([]uint64, 32*r) 312 | } 313 | 314 | for pass <= 1 { 315 | if isYescrypt { 316 | if pass == 1 { 317 | prehash = prehash[:8] 318 | } 319 | h := hmac.New(sha256.New, prehash) 320 | h.Write(*ppassword) 321 | passwordSha256 := h.Sum(nil) 322 | ppassword = &passwordSha256 323 | } 324 | 325 | b := pbkdf2.Key(*ppassword, salt, 1, p*128*r, sha256.New) 326 | 327 | if isYescrypt { 328 | copy(*ppassword, b[:32]) 329 | smixYescrypt(b, r, N, v, xy, *ppassword) 330 | } else { 331 | for i := 0; i < p; i++ { 332 | smix(b[i*128*r:], r, N, N, v, xy, nil) 333 | } 334 | } 335 | 336 | key = pbkdf2.Key(*ppassword, b, 1, max(keyLen, 32), sha256.New) 337 | 338 | if isYescrypt { 339 | if pass == 0 { 340 | copy(*ppassword, key[:32]) 341 | N <<= 6 342 | } else { 343 | h1 := hmac.New(sha256.New, key[:32]) 344 | h1.Write([]byte("Client Key")) 345 | h2 := sha256.New() 346 | h2.Write(h1.Sum(nil)) 347 | copy(key, h2.Sum(nil)) 348 | } 349 | } 350 | 351 | pass++ 352 | } 353 | 354 | return key[:keyLen], nil 355 | } 356 | 357 | // Classic scrypt 358 | // 359 | // ScryptKey implements classic scrypt (not yescrypt). It is compatible with 360 | // the x/crypto scrypt module's Key. 361 | // 362 | // It derives a key from the password, salt and cost parameters, returning a 363 | // byte slice of length keyLen that can be used as cryptographic key. 364 | // 365 | // N is a CPU/memory cost parameter, which must be a power of two greater than 1. 366 | // r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the 367 | // limits, the function returns a nil byte slice and an error. 368 | // 369 | // For example, you can get a derived key for e.g. AES-256 (which needs a 370 | // 32-byte key) by doing: 371 | // 372 | // dk, err := yescrypt.ScryptKey([]byte("some password"), salt, 32768, 8, 1, 32) 373 | // 374 | // The recommended parameters for interactive logins as of 2017 are N=32768, r=8 375 | // and p=1. The parameters N, r, and p should be increased as memory latency and 376 | // CPU parallelism increases; consider setting N to the highest power of 2 you 377 | // can derive within 100 milliseconds. Remember to get a good random salt. 378 | func ScryptKey(password, salt []byte, N, r, p, keyLen int) ([]byte, error) { 379 | return deriveKey(password, salt, N, r, p, keyLen, false) 380 | } 381 | 382 | // Native yescrypt 383 | // 384 | // Key is similar to ScryptKey, but computes native yescrypt assuming 385 | // reference yescrypt's current default flags (as of yescrypt 1.1.0), p=1 386 | // (which it currently requires), t=0, and no ROM. Example usage: 387 | // 388 | // dk, err := yescrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) 389 | // 390 | // The set of parameters accepted by Key will likely change in future versions 391 | // of this Go module to support more yescrypt functionality. 392 | func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) { 393 | return deriveKey(password, salt, N, r, p, keyLen, true) 394 | } 395 | --------------------------------------------------------------------------------