Golang Can someone explain why the compare of hash is fail - go

I am trying to develop a user login system, in order for that I am testing the bcrypt function of golang. But I faced some funny situation.
My bcrypt learning material is come from this, the code works well
https://medium.com/#jcox250/password-hash-salt-using-golang-b041dc94cb72
But when I wrote my own code, it keep fail in comparison.
package main
import (
"log"
"golang.org/x/crypto/bcrypt"
)
func main() {
hash1, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.MinCost)
hash2, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.MinCost)
err := bcrypt.CompareHashAndPassword(hash1, hash2)
if err != nil {
log.Println(err)
} else {
log.Println("success")
}
}
Since the string for hashing is the same "123456", I except the output of my code should be success, but the outcome is crypto/bcrypt: hashedPassword is not the hash of the given password.
Can someone explain this and guide me.

The documentation for the function you are using says it compares a hash to a plaintext password - not a hash to a hash:
CompareHashAndPassword compares a bcrypt hashed password with its possible plaintext equivalent. Returns nil on success, or an error on failure.
If you were to print or compare each of the generated hashes, they would not match exactly either (that's kind of the point). But you should be able to use the CompareHashAndPassword function to check if a password was used to generate the given hash.
Try this:
err := bcrypt.CompareHashAndPassword(hash1, []byte("123456"))
if err != nil {
log.Println(err)
} else {
log.Println("success")
}

Related

unserialize php in goland

I have a file with serialized array in PHP.
The content of the file locks like this
a:2:{i:250;s:7:"my_catz";s:7:"abcd.jp";a:2:{s:11:"category_id";i:250;s:13:"category_name";s:7:"my_catz";}}
The array unserialized is this
(
[250] => my_catz
[abcd.jp] => Array
(
[category_id] => 250
[category_name] => my_catz
)
)
Now, i want to get the content of the file in GO, unserialize it convert it to an array.
In GO i can get the content of the file using
dat, err := os.ReadFile("/etc/squid3/compiled-categories.db")
if err != nil {
if e.Debug {
log.Printf("error reading /etc/squid3/compiled-categories.db: ", err)
}
}
And unserialized it using github.com/techoner/gophp library
package categorization
import (
"fmt"
"os"
"github.com/techoner/gophp"
"log"
"errors"
)
type Data struct {
Website string
Debug bool
}
func (e Data) CheckPersonalCategories() (int,string) {
if e.Debug {
log.Printf("Checking Personal Categories")
}
if _, err := os.Stat("/etc/squid3/compiled-categories.db"); errors.Is(err, os.ErrNotExist) {
if e.Debug {
log.Printf("/etc/squid3/compiled-categories.db not exit: ", err)
}
return 0,""
}
dat, err := os.ReadFile("/etc/squid3/compiled-categories.db")
if err != nil {
if e.Debug {
log.Printf("error reading /etc/squid3/compiled-categories.db: ", err)
}
}
out, _ := gophp.Unserialize(dat)
fmt.Println(out["abcd.jp"])
return 0,""
}
But I can't access to the array, for example, when I try access to array key using out["abcd.jp"] i get this error message
invalid operation: out["abcd.jp"] (type interface {} does not support indexing)
The result of out is
map[250:my_catz abcd.jp:map[category_id:250 category_name:my_catz]]
Seams that is unserializing
Don't make assumptions about what is and isn't succeeding in your code. Error responses are the only reliable way to know whether a function succeeded. In this case the assumption may hold, but ignoring errors is always a mistake. Invest time in catching errors and at least panic them - don't instead waste your time ignoring errors and then trying to debug unreliable code.
invalid operation: out["abcd.jp"] (type interface {} does not support indexing)
The package you're using unfortunately doesn't provide any documentation so you have to read the source to understand that gophp.Unserialize returns (interface{}, error). This makes sense; php can serialize any value, so Unserialize must be able to return any value.
out is therefore an interface{} whose underlying value depends on the data. To turn an interface{} into a particular value requires a type assertion. In this case, we think the underlying data should be map[string]interface{}. So we need to do a type assertion:
mout, ok := out.(map[string]interface{})
Before we get to the working code, one more point I'd like you to think about. Look at the code below: I started it from your code, but the resemblance is very slight. I took out almost all the code because it was completely irrelevant to your question. I added the input data to the code to make a minimal reproduction of your code (as I asked you to do and you declined to do). This is a very good use of your time for 2 reasons: first, it makes it a lot easier to get answers (both because it shows sufficient effort on your part and because it simplifies the description of the problem), and second, because it's excellent practice for debugging. I make minimal reproductions of code flows all the time to better understand how to do things.
You'll notice you can run this code now without any additional effort. That's the right way to provide a minimal reproducible example - not with a chunk of mostly irrelevant code which still can't be executed by anybody.
The Go Plaground is a great way to demonstrate go-specific code that others can execute and investigate. You can also see the code below at https://go.dev/play/p/QfCl08Gx53e
package main
import (
"fmt"
"github.com/techoner/gophp"
)
type Data struct {
Website string
Debug bool
}
func main() {
var dat = []byte(`a:2:{i:250;s:7:"my_catz";s:7:"abcd.jp";a:2:{s:11:"category_id";i:250;s:13:"category_name";s:7:"my_catz";}}`)
out, err := gophp.Unserialize(dat)
if err != nil {
panic(err)
}
if mout, ok := out.(map[string]interface{}); ok {
fmt.Println(mout["abcd.jp"])
}
}

Import external user to firebase

I want to import users from an external database to firebase.
The password were hashed with a sha256 function with the password prepended by a salt (which is a UUID).
For example:
password = "123qwerty!"
salt = "cb60eb29-95a2-418e-be2a-c1c107fb1add"
hash = sha256(salt+password)
# 54ccb21d42c6961aa1b666b7cb0485f85aab2f2323399fb2959ea5e4e9f6f595
Now to import this to firebase I would do the following:
users = []*auth.UserToImport
users = append(users, (&auth.UserToImport{}).
UID("some-uid").
Email("jon.foo#example.com").
PasswordHash([]byte("54ccb21d42c6961aa1b666b7cb0485f85aab2f2323399fb2959ea5e4e9f6f595")).
PasswordSalt([]byte("cb60eb29-95a2-418e-be2a-c1c107fb1add")).
DisplayName("Jon FOO"))
h := hash.SHA256{
Rounds: 1,
InputOrder: hash.InputOrderSaltFirst,
}
res, err := cl.ImportUsers(ctx, users, auth.WithHash(h))
if err != nil {
log.Fatal(err)
}
The user is well imported in firebase (I can see it in the console), but when I try to login, I have this error The password is invalid or the user does not have a password.
I cannot see what is wrong with my way, maybe the Rounds parameter should be updated, but to what value?
Thanks!
I finally found my issue.
In my case I was giving as the PasswordHash the hex representation of the password:
PasswordHash([]byte("54ccb21d42c6961aa1b666b7cb0485f85aab2f2323399fb2959ea5e4e9f6f595")).
It turns out I have to decode first the password, like the following:
decoded, err := hex.DecodeString("54ccb21d42c6961aa1b666b7cb0485f85aab2f2323399fb2959ea5e4e9f6f595")
if err != nil {
return err
}
user := (&auth.UserToImport{}).
PasswordHash(decoded).
PasswordSalt([]byte("cb60eb29-95a2-418e-be2a-c1c107fb1add")). // the salt stays the same
...
// call ImportUsers with the same hash configuration (Rounds: 1, InputOrder: SaltFirst)
After updating this I ran the code and I could now authenticate with my imported user.
Quick note: as mentionned in the comment, the node SDK does not have the option to specify the input order (salt or password first), this seems to be an important missing feature.

In Go, how to verify that the data type of an input from the user matches the data type of the code?

I am new to Go.
Currently, I am creating a menu in Go and I want to verify that the data type of the input from the user matches the data type of the variable defined in the code. Part of my code looks like this so far:
package main
import (
"fmt"
"reflect"
)
var option int // The variable is declared outside of the main().
func general_menu() {
fmt.Println(".......................General Menu..................................")
fmt.Println()
fmt.Println("Calculator..........................................................1")
fmt.Println("Linear algebra package..............................................2")
fmt.Println("Language change.....................................................9")
fmt.Println("Exit...............................................................10")
fmt.Println()
fmt.Println("Choose an option from the menu.")
fmt.Println()
fmt.Scan(&option)
fmt.Println()
if (option != 1 && option != 2 && option != 9 && option != 10)||reflect.TypeOf(option)!=int{
fmt.Println("Wrong option input. Please, try again.")
fmt.Println()
general_menu()
}
}
I know that this doens't work this way, and I know that "int" can not be used as part of an "if" condirion.
I would kindly appreciate any suggestions on the proper way to solve this problem.
Thanks.
Edit: I have added more of my code as kindly suggested by the contributors.
Edit: Based on the answer provided, I have tried to implement a function, but the syntax is still not correct:
func check_integers_are_not_string(x int) bool {
change := strconv.Itoa(x)
if change != nil {
return true
} else {
return false
}
} // This function returns a true boolean value if conversion from int to string was possible, meaning that the entered value is a string.
Just read the documentation of Scan - https://pkg.go.dev/fmt#Scan
It returns the number of successfully read arguments and an error. The input is mapped in your case to a variable of type int, so if a user inputs a string it will return 0 and an error. Otherwise it will return 1 and the error should be nil. You can check for that.
n, err := fmt.Scan(&option)
if n != 1 || err != nil {
// print error and go back
}
One common way to do it is to try to make the conversion and see if it succeeds.
optionInt, err := strconv.Atoi(option) // Assuming option is of type string
if err != nil {
log.Printf("String '%s' cannot be converted to type int: %v", option, err)
os.Exit(1)
}
log.Printf(`optionInt is %d.`, optionInt)
This is a good approach if you are only interested in conversion to one type. Otherwise things can quickly get more involved, utilizing constructs such as lexers and parsers, but that would warrant more information on what you are trying to accomplish.

To what extent are errors strings guaranteed to not change?

One of the main issues I have with Golang is that the error handling is basically a check for a string (I would love to be wrong, do not hesitate :))
In the example below, I am trying to create a directory, but will have different behaviour depending on the kind of issue. Specifically, if a directory exists I will just pass.
package main
import (
"fmt"
"os"
)
func main() {
err := os.Mkdir("test", 0644)
if err != nil {
fmt.Printf("error: %v", err)
if err.Error() == "mkdir test: Cannot create a file when that file already exists" {
fmt.Printf("the dir already exists")
} else {
panic(err)
}
}
}
It does not work, repeated attempts are not logged. Why? Ah, crap, I forgot the dot at the end of the mkdir test: Cannot create a file when that file already exists string.
I feel that relying on an error string is fragile, as opposed to having something like err.ErrorType().DirectoryExists() kind of check (which sometimes exists, in net for instance).
My question: to what extent can I rely on the fact that the error strings will not change? (in other words, that mkdir test: Cannot create a file when that file already exists. will not be worded differently, or ported to another national language, etc.)
I had some hope with errors.Is() but it ultimately relies on the string comparison.
Go error strings don't change arbitrarily, but they also aren't covered by the Go compatibility policy: they can be changed if the increase in clarity outweighs the (inevitable) cost of breaking programs that make (fragile, unsupported) assumptions about the string contents.
The errors package is the robust way to check for specific types of errors.
Use errors.Is to check for equivalence to a canonical error (https://play.golang.org/p/co6ukgQrr58):
err := os.Mkdir(dir, 0644)
if errors.Is(err, os.ErrExist) {
t.Logf("the dir already exists")
} else if err != nil {
t.Fatal(err)
}
Use errors.As to check for a particular type of error (https://play.golang.org/p/UR1nUCRMUY6):
err := os.Mkdir(dir, 0644)
var pe *os.PathError
if errors.As(err, &pe) {
t.Logf("error creating %q: %v", pe.Path, pe.Err)
} else if err != nil {
t.Fatal(err)
}
In this case, you can use os.IsExist(err)
err := os.Mkdir("test", 0644)
if err != nil {
if os.IsExist(err){
fmt.Printf("the dir already exists")
} else {
panic(err)
}
}
Good libraries should allow you to inspect errors without relying on string comparison. Various methods exist to do so:
Comparaison with sentinel values if err == os.EOF
Utility function: os.IsExist(err)
Type assertion: pathErr := err.(*os.PathError)
There is always a way to inspect errors in the standard library without relying on strings. Check the function/package documentation for details about how to do it.
Note:
errors.Is() and errors.As() are a (~recent) generalisation of == and type assertion but for errors that could contain other errors. See https://go.dev/blog/go1.13-errors
From https://pkg.go.dev/os#Mkdir:
Mkdir creates a new directory with the specified name and permission bits (before umask). If there is an error, it will be of type *PathError.
This means you could type-assert the returned error to get more information.
if err != nil {
pathErr := err.(*os.PathError)
}
With errors returned from functions in package os specifically, also take note of these two functions:
https://pkg.go.dev/os#IsExist
https://pkg.go.dev/os#IsNotExist
to what extent can I rely on the fact that the error strings will not change?
To the extent which is guaranteed by the function's contract, which as in most programming languages conventionally is written in documenting comments above the function. In the case of os.MkDir(): you cannot.

Verifying signature of payload in Go

I am verifying the identity of the sender of a piece of data. I am provided the RSA public key in a PEM format and I know the data is passed through the SHA256 hashing function. The equivalent verification on the node.js platform:
Ticket.prototype.verify = function (ticket) {
if (!ticket) return null;
var pubkey = fs.readFileSync('/etc/SCAMP/auth/ticket_verify_public_key.pem');
var parts = ticket.split(',');
if (parts[0] != '1') return null;
var sig = new Buffer(parts.pop().replace(/-/g,'+').replace(/_/g,'/'), 'base64');
var valid = crypto.createVerify('sha256').update( new Buffer(parts.join(',')) ).verify( pubkey, sig )
Which can verify:
1,3063,21,1438783424,660,1+20+31+32+34+35+36+37+38+39+40+41+42+43+44+46+47+48+50+53+56+59+60+61+62+67+68+69+70+71+75+76+80+81+82+86+87+88+102+104+105+107+109+110+122+124,PcFNyWjoz_iiVMgEe8I3IBfzSlUcqUGtsuN7536PTiBW7KDovIqCaSi_8nZWcj-j1dfbQRA8mftwYUWMhhZ4DD78-BH8MovNVucbmTmf2Wzbx9bsI-dmUADY5Q2ol4qDXG4YQJeyZ6f6F9s_1uxHTH456QcsfNxFWh18ygo5_DVmQQSXCHN7EXM5M-u2DSol9MSROeBolYnHZyE093LgQ2veWQREbrwg5Fcp2VZ6VqIC7yu6f_xYHEvU0-ZsSSRMAMUmhLNhmFM4KDjl8blVgC134z7XfCTDDjCDiynSL6b-D-
by splitting on the last ,. The left side of the split is the ticket data I care about, the right side is the signature which I need to verify before I can use the ticket data.
I have tried to port the logic to go:
func TestSigVerification(t *testing.T) {
block, _ := pem.Decode(signingPubKey)
if block == nil {
t.Errorf("expected to block to be non-nil CERTIFICATE", block)
}
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
t.Errorf("could not parse PKIXPublicKey: `%s`", key)
}
rsaPubKey, ok := key.(*rsa.PublicKey)
if !ok {
t.Errorf("couldn't cast to rsa.PublicKey!")
}
ticket,_ := ParseTicketBytes(fullTicketBytes)
h := sha256.New()
h.Write(ticketBytes)
digest := h.Sum(nil)
err = rsa.VerifyPKCS1v15(rsaPubKey, crypto.SHA256, digest, ticket.Signature)
if err != nil {
t.Errorf("could not verify ticket: `%s` (digest: `%v`)", err, digest )
}
}
But I'm pretty sure VerifyPKCS1v15 is not equivalent to node's crypto.createVerify and this test case fails. What should I be using? How can I use the public key to decrypt the signature and get the sha256? once I have the decrypted sha256 value I could just do a basic comparison with the sha256 I have generated.
Here's a runnable playground example: http://play.golang.org/p/COx2OG-AiA
Though I couldn't get it to work, I suspect the issue is that you'll need to convert the sig from base64 into bytes via the base64 encoding. See this example here:
http://play.golang.org/p/bzpD7Pa9mr (especially lines 23 to 28, where they have to encode the sig from bytes to base64 string to print it, then feed the byte version into the sig check, indicating that you have to use the byte version and not base64 string)
Which I stumbled across on this post:
Signing and decoding with RSA-SHA in GO
I've found that golang generally expects bytes everywhere in byte encoding. I tried to decode your sig string from base64 to bytes however, even after replacing the '-' with '+' and the '_' with '/' it still won't work, for reasons unknown to me:
http://play.golang.org/p/71IiV2z_t8
At the very least this seems to indicate that maybe your sig is bad? If it isn't valid base64? I think if you can find a way to solve this the rest should work!
I tried running your code and it doesn't look like your ticket is well formed. It's not long enough. Where did you get the value from?
Double check that ticket -- that may just be enough to get you going.

Resources