-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tommi2Day
committed
May 24, 2024
1 parent
bc274fa
commit ab48483
Showing
4 changed files
with
113 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package pwlib | ||
|
||
// https://ferdinand-neman.medium.com/ssha-password-hash-with-golang-7d79d792bd3d | ||
import ( | ||
"bytes" | ||
//nolint gosec | ||
"crypto/sha1" | ||
"encoding/base64" | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
type SSHAEncoder struct { | ||
} | ||
|
||
// Encode encodes the []byte of raw password | ||
func (enc SSHAEncoder) Encode(rawPassPhrase []byte) ([]byte, error) { | ||
salt, err := makeSSHASalt() | ||
if err != nil { | ||
return []byte{}, err | ||
} | ||
hash := makeSSHAHash(rawPassPhrase, salt) | ||
b64 := base64.StdEncoding.EncodeToString(hash) | ||
return []byte(fmt.Sprintf("{SSHA}%s", b64)), nil | ||
} | ||
|
||
// Matches matches the encoded password and the raw password | ||
func (enc SSHAEncoder) Matches(encodedPassPhrase, rawPassPhrase []byte) bool { | ||
// strip the {SSHA} | ||
eppS := string(encodedPassPhrase) | ||
if strings.HasPrefix(string(encodedPassPhrase), "{SSHA}") { | ||
eppS = string(encodedPassPhrase)[6:] | ||
} | ||
hash, err := base64.StdEncoding.DecodeString(eppS) | ||
if err != nil { | ||
return false | ||
} | ||
salt := hash[len(hash)-4:] | ||
//nolint gosec | ||
sha := sha1.New() | ||
_, _ = sha.Write(rawPassPhrase) | ||
_, _ = sha.Write(salt) | ||
sum := sha.Sum(nil) | ||
|
||
// compare without the last 4 bytes of the hash with the calculated hash | ||
return bytes.Equal(sum, hash[:len(hash)-4]) | ||
} | ||
|
||
// makeSSHASalt make 4Byte salt for SSHA hashing | ||
func makeSSHASalt() (salt []byte, err error) { | ||
salt, err = makeSalt(4) | ||
return | ||
} | ||
|
||
// makeSSHAHash make hasing using SHA-1 with salt. This is not the final output though. You need to append {SSHA} string with base64 of this hash. | ||
func makeSSHAHash(passphrase, salt []byte) []byte { | ||
//nolint gosec | ||
sha := sha1.New() | ||
_, _ = sha.Write(passphrase) | ||
_, _ = sha.Write(salt) | ||
|
||
h := sha.Sum(nil) | ||
return append(h, salt...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package pwlib | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var sshaPlain = []byte("password") | ||
|
||
func TestSSHA(t *testing.T) { | ||
t.Run("TestSSHAEncoder_Encode", func(t *testing.T) { | ||
enc := SSHAEncoder{} | ||
encoded, err := enc.Encode(sshaPlain) | ||
require.NoError(t, err) | ||
assert.Contains(t, string(encoded), "{SSHA}") | ||
assert.Greater(t, len(encoded), 6) | ||
t.Log(string(encoded)) | ||
}) | ||
|
||
t.Run("TestSSHAEncoder_Matches", func(t *testing.T) { | ||
enc := SSHAEncoder{} | ||
encoded, err := enc.Encode(sshaPlain) | ||
require.NoError(t, err) | ||
assert.True(t, enc.Matches(encoded, sshaPlain)) | ||
}) | ||
|
||
t.Run("TestMakeSSHAHash", func(t *testing.T) { | ||
salt, err := makeSSHASalt() | ||
require.NoError(t, err) | ||
hash := makeSSHAHash(sshaPlain, salt) | ||
assert.Equal(t, 24, len(hash)) | ||
t.Log(hash) | ||
}) | ||
|
||
t.Run("TestMakeSalt", func(t *testing.T) { | ||
salt, err := makeSSHASalt() | ||
require.NoError(t, err) | ||
assert.Equal(t, 4, len(salt)) | ||
}) | ||
} |