]> Cypherpunks.ru repositories - balloon.git/blobdiff - balloon.go
Fix bug with a possible race when running with multiple jobs
[balloon.git] / balloon.go
index 9bf2d37ee0dc8f268b49f1c35c60b30f23cd9ce9..8e753dee0762da41161c991fb82c487a96ac342b 100644 (file)
@@ -1,19 +1,20 @@
 /*
 balloon -- Balloon password hashing function
-Copyright (C) 2016-2017 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GNU Lesser General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
+You should have received a copy of the GNU Lesser General Public
+License along with this program.  If not, see
+<http://www.gnu.org/licenses/>.
 */
 
 // Balloon password hashing.
@@ -51,48 +52,49 @@ const (
 //                buf[m] = hash(cnt++ || buf[m] || buf[other])
 //    # Extract output from buffer.
 //    return buf[sCost-1]
-func B(h hash.Hash, passwd, salt []byte, sCost, tCost int) []byte {
+func B(h hash.Hash, passwd, salt []byte, sCost, tCost uint64) []byte {
        var cnt uint64
        intBuf := make([]byte, 8)
-       buf := make([][]byte, sCost)
+       hSize := uint64(h.Size())
+       buf := make([]byte, 0, sCost*hSize)
        // Expand input into buffer
        binary.BigEndian.PutUint64(intBuf, cnt)
        cnt++
        h.Write(intBuf)
        h.Write(passwd)
        h.Write(salt)
-       buf[0] = h.Sum(nil)
-       var m int
+       buf = h.Sum(buf)
+       var m uint64
        for m = 1; m < sCost; m++ {
                binary.BigEndian.PutUint64(intBuf, cnt)
                cnt++
                h.Reset()
                h.Write(intBuf)
-               h.Write(buf[m-1])
-               buf[m] = h.Sum(nil)
+               h.Write(buf[(m-1)*hSize : m*hSize])
+               buf = h.Sum(buf)
        }
        // Mix buffer contents
        var prev []byte
-       var i int
+       var i uint64
+       var neigh uint64
        bi := big.NewInt(0)
        bs := big.NewInt(int64(sCost))
        biBuf := make([]byte, 0, h.Size())
-       var other int
-       for t := 0; t < tCost; t++ {
+       for t := uint64(0); t < tCost; t++ {
                for m = 0; m < sCost; m++ {
                        // Hash last and current blocks
                        if m == 0 {
-                               prev = buf[len(buf)-1]
+                               prev = buf[(sCost-1)*hSize:]
                        } else {
-                               prev = buf[m-1]
+                               prev = buf[(m-1)*hSize : m*hSize]
                        }
                        binary.BigEndian.PutUint64(intBuf, cnt)
                        cnt++
                        h.Reset()
                        h.Write(intBuf)
                        h.Write(prev)
-                       h.Write(buf[m])
-                       buf[m] = h.Sum(buf[m][:0])
+                       h.Write(buf[m*hSize : (m+1)*hSize])
+                       buf = h.Sum(buf[:m*hSize])
 
                        // Hash in pseudorandomly chosen blocks
                        for i = 0; i < delta; i++ {
@@ -101,28 +103,28 @@ func B(h hash.Hash, passwd, salt []byte, sCost, tCost int) []byte {
                                h.Reset()
                                h.Write(intBuf)
                                h.Write(salt)
-                               binary.BigEndian.PutUint64(intBuf, uint64(t))
+                               binary.BigEndian.PutUint64(intBuf, t)
                                h.Write(intBuf)
-                               binary.BigEndian.PutUint64(intBuf, uint64(m))
+                               binary.BigEndian.PutUint64(intBuf, m)
                                h.Write(intBuf)
-                               binary.BigEndian.PutUint64(intBuf, uint64(i))
+                               binary.BigEndian.PutUint64(intBuf, i)
                                h.Write(intBuf)
                                biBuf = h.Sum(biBuf[:0])
                                bi.SetBytes(biBuf)
                                bi.Mod(bi, bs)
-                               other = int(bi.Uint64())
                                binary.BigEndian.PutUint64(intBuf, cnt)
                                cnt++
                                h.Reset()
                                h.Write(intBuf)
-                               h.Write(buf[m])
-                               h.Write(buf[other])
-                               buf[m] = h.Sum(buf[m][:0])
+                               h.Write(buf[m*hSize : (m+1)*hSize])
+                               neigh = bi.Uint64()
+                               h.Write(buf[neigh*hSize : (neigh+1)*hSize])
+                               buf = h.Sum(buf[:m*hSize])
                        }
                }
        }
        // Extract output from buffer
-       return buf[sCost-1]
+       return buf[(sCost-1)*hSize:]
 }
 
 // This function adds additional functionality over pure B(): ability to
@@ -139,9 +141,10 @@ func H(hasher func() hash.Hash, passwd, salt []byte, sCost, tCost int, jobs int)
        results := make(chan []byte)
        for ; i < jobs; i++ {
                go func(i int) {
-                       saltBuf := make([]byte, 8)
-                       binary.BigEndian.PutUint64(saltBuf, uint64(i))
-                       results <- B(hasher(), passwd, append(salt, saltBuf...), sCost, tCost)
+                       saltBuf := make([]byte, len(salt)+8)
+                       copy(saltBuf, salt)
+                       binary.BigEndian.PutUint64(saltBuf[len(salt):], uint64(i))
+                       results <- B(hasher(), passwd, saltBuf, uint64(sCost), uint64(tCost))
                }(i)
        }
        h := hasher()