]> Cypherpunks.ru repositories - balloon.git/blobdiff - balloon.go
Unify copyright comment format
[balloon.git] / balloon.go
index 753ff224003d438021f33717756ebd77fc39fed1..137ee2180e4603845942ab1a384741577aa0e635 100644 (file)
@@ -1,20 +1,18 @@
-/*
-balloon -- Balloon password hashing function
-Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as
-the Free Software Foundation, version 3 of the License.
-
-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 Lesser General Public License for more details.
-
-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 -- Balloon password hashing function
+// Copyright (C) 2016-2024 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// the Free Software Foundation, version 3 of the License.
+//
+// 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 Lesser General Public License for more details.
+//
+// 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.
 //
@@ -27,37 +25,35 @@ import (
        "math/big"
 )
 
-const (
-       delta = 3
-)
+const delta = 3
 
 // This function takes hash, password, salt, space cost (buffer size,
 // number of hash-output sized blocks), time cost (number of rounds) and
 // performs the following:
 //
-//    # Expand input into buffer.
-//    buf[0] = hash(cnt++ || passwd || salt)
-//    for m from 1 to sCost-1:
-//        buf[m] = hash(cnt++ || buf[m-1])
-//    # Mix buffer contents.
-//    for t from 0 to tCost-1:
-//        for m from 0 to sCost-1:
-//            # Hash last and current blocks.
-//            prev = buf[(m-1) mod sCost]
-//            buf[m] = hash(cnt++ || prev || buf[m])
-//            # Hash in pseudorandomly chosen blocks.
-//            for i from 0 to delta-1:
-//                other = to_int(hash(cnt++ || salt || t || m || i)) mod sCost
-//                buf[m] = hash(cnt++ || buf[m] || buf[other])
-//    # Extract output from buffer.
-//    return buf[sCost-1]
+//     # Expand input into buffer.
+//     buf[0] = hash(cnt++ || passwd || salt)
+//     for m from 1 to sCost-1:
+//         buf[m] = hash(cnt++ || buf[m-1])
+//     # Mix buffer contents.
+//     for t from 0 to tCost-1:
+//         for m from 0 to sCost-1:
+//             # Hash last and current blocks.
+//             prev = buf[(m-1) mod sCost]
+//             buf[m] = hash(cnt++ || prev || buf[m])
+//             # Hash in pseudorandomly chosen blocks.
+//             for i from 0 to delta-1:
+//                 other = to_int(hash(cnt++ || salt || t || m || i)) mod sCost
+//                 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 uint64) []byte {
        var cnt uint64
        intBuf := make([]byte, 8)
        hSize := uint64(h.Size())
        buf := make([]byte, 0, sCost*hSize)
        // Expand input into buffer
-       binary.BigEndian.PutUint64(intBuf, cnt)
+       binary.LittleEndian.PutUint64(intBuf, cnt)
        cnt++
        h.Write(intBuf)
        h.Write(passwd)
@@ -65,7 +61,7 @@ func B(h hash.Hash, passwd, salt []byte, sCost, tCost uint64) []byte {
        buf = h.Sum(buf)
        var m uint64
        for m = 1; m < sCost; m++ {
-               binary.BigEndian.PutUint64(intBuf, cnt)
+               binary.LittleEndian.PutUint64(intBuf, cnt)
                cnt++
                h.Reset()
                h.Write(intBuf)
@@ -87,7 +83,7 @@ func B(h hash.Hash, passwd, salt []byte, sCost, tCost uint64) []byte {
                        } else {
                                prev = buf[(m-1)*hSize : m*hSize]
                        }
-                       binary.BigEndian.PutUint64(intBuf, cnt)
+                       binary.LittleEndian.PutUint64(intBuf, cnt)
                        cnt++
                        h.Reset()
                        h.Write(intBuf)
@@ -97,21 +93,27 @@ func B(h hash.Hash, passwd, salt []byte, sCost, tCost uint64) []byte {
 
                        // Hash in pseudorandomly chosen blocks
                        for i = 0; i < delta; i++ {
-                               binary.BigEndian.PutUint64(intBuf, cnt)
-                               cnt++
                                h.Reset()
+                               binary.LittleEndian.PutUint64(intBuf, t)
                                h.Write(intBuf)
-                               h.Write(salt)
-                               binary.BigEndian.PutUint64(intBuf, t)
+                               binary.LittleEndian.PutUint64(intBuf, m)
                                h.Write(intBuf)
-                               binary.BigEndian.PutUint64(intBuf, m)
+                               binary.LittleEndian.PutUint64(intBuf, i)
                                h.Write(intBuf)
-                               binary.BigEndian.PutUint64(intBuf, i)
+                               biBuf = h.Sum(biBuf[:0])
+                               binary.LittleEndian.PutUint64(intBuf, cnt)
+                               cnt++
+                               h.Reset()
                                h.Write(intBuf)
+                               h.Write(salt)
+                               h.Write(biBuf)
                                biBuf = h.Sum(biBuf[:0])
+                               for i, j := 0, len(biBuf)-1; i < j; i, j = i+1, j-1 {
+                                       biBuf[i], biBuf[j] = biBuf[j], biBuf[i]
+                               }
                                bi.SetBytes(biBuf)
                                bi.Mod(bi, bs)
-                               binary.BigEndian.PutUint64(intBuf, cnt)
+                               binary.LittleEndian.PutUint64(intBuf, cnt)
                                cnt++
                                h.Reset()
                                h.Write(intBuf)
@@ -130,11 +132,11 @@ func B(h hash.Hash, passwd, salt []byte, sCost, tCost uint64) []byte {
 // run several hashers (jobs) simultaneously and second-preimage resistant
 // password double hashing.
 //
-//     H(p, s, jobs) = hash(p || s || (
-//         B(p, s || "1") XOR
-//         B(p, s || "2") XOR
-//         B(p, s || jobs)
-//     ))
+//     H(p, s, jobs) = hash(p || s || (
+//         B(p, s || "1") XOR
+//         B(p, s || "2") XOR
+//         B(p, s || jobs)
+//     ))
 func H(hasher func() hash.Hash, passwd, salt []byte, sCost, tCost int, jobs int) []byte {
        var i int
        results := make(chan []byte)
@@ -142,7 +144,7 @@ func H(hasher func() hash.Hash, passwd, salt []byte, sCost, tCost int, jobs int)
                go func(i int) {
                        saltBuf := make([]byte, len(salt)+8)
                        copy(saltBuf, salt)
-                       binary.BigEndian.PutUint64(saltBuf[len(salt):], uint64(i))
+                       binary.LittleEndian.PutUint64(saltBuf[len(salt):], uint64(i))
                        results <- B(hasher(), passwd, saltBuf, uint64(sCost), uint64(tCost))
                }(i)
        }