1. Сделал так:
func (kbr keyBytesReader) Read(p []byte) (n int, err error) {
n = copy(p, (*kbr.key)[*kbr.offset:])
if n < len(p) {
err = bytes.ErrTooLarge
}
*kbr.offset += n
return
}
func PasswordToPrivateKey(password string) (privateKey *rsa.PrivateKey, err error) {
dk := pbkdf2.Key([]byte(password), []byte(salt), 1024, 512*1024, sha512.New)
kbr := keyBytesReader{&dk, new(int)}
privateKey, err = rsa.GenerateKey(kbr, 4096)
return
}
И это не работает, т.к.:
1. (решаемо) нет повторяемости результата генерации ключа по результату работы pbkdf2.Key в качестве рандома.
2. (не решаемо или сложно решаемо) в RSA-ключе должны быть простые числа. Т.е. далеко не всякий рандомный набор байт подойдёт.
Ну и чисто в теории пароль обладает много меньшей энтропией, чем 4096-битный RSA-ключ.
Так что решил сделать в своём приложении так:
Под ответственность юзера организовать хранение его приватного ключа за паролем. С лимитом на кол-во попыток подбора пароля на ip, на сам ключ и на сервис целиком.
Ключевое здесь - это перекладывание ответственности. Т.е. если юзер хочет сильной криптографией, он не будет пользоваться этой функцией.
2. За то работает для криптографии на эллиптических кривых:
argon2Key := argon2.IDKey([]byte(password), []byte(salt), 1, 64*1024, 4, 128)
privateKey, err = ecdsa.GenerateKey(elliptic.P521(), bytes.NewReader(argon2Key))