cryptoballot /
rsablind
| 1 | package rsablind |
||
| 2 | |||
| 3 | import ( |
||
| 4 | "crypto/rand" |
||
| 5 | "crypto/rsa" |
||
| 6 | "crypto/subtle" |
||
| 7 | "io" |
||
| 8 | "math/big" |
||
| 9 | ) |
||
| 10 | |||
| 11 | // Blind blinds the hashes message. |
||
| 12 | // |
||
| 13 | // Given the Public Key of the signing entity and a hashed message, blind the message so it cannot be inspected by the signing entity. |
||
| 14 | // |
||
| 15 | // Use the Full-Domain-Hash package (https://github.com/cryptoballot/fdh) to expand the size of your hash to a secure size. You should |
||
| 16 | // use a full-domain-hash size of at least 1024 bits, but bigger is better. However, this hash size needs to remain significantly |
||
| 17 | // smaller than your key size to avoid RSA verification failures. A good rule of thumb is to use 2048 bit keys and 1536 bit hashes, |
||
| 18 | // or 4096 bit keys and 3072 bit hashes (hash size is 3/4 the key size). |
||
| 19 | // |
||
| 20 | // This function returns the blinded message and an unblinding factor that can be used in conjunction with the `Unblind()` function to |
||
| 21 | // unblind the signature after the message has been signed. |
||
| 22 | func Blind(key *rsa.PublicKey, hashed []byte) (blindedData []byte, unblinder []byte, err error) { |
||
| 23 | bitlen := key.N.BitLen() |
||
| 24 | if len(hashed)*8 > bitlen { |
||
| 25 | return nil, nil, rsa.ErrMessageTooLong |
||
| 26 | } |
||
| 27 | |||
| 28 | blinded, unblinderBig, err := blind(rand.Reader, key, new(big.Int).SetBytes(hashed)) |
||
| 29 | if err != nil { |
||
| 30 | return nil, nil, err |
||
| 31 | } |
||
| 32 | |||
| 33 | return blinded.Bytes(), unblinderBig.Bytes(), nil |
||
| 34 | } |
||
| 35 | |||
| 36 | // BlindSign signs the provided hashed message blindly. |
||
| 37 | // |
||
| 38 | // The private key used here should not be used for any other purpose other than blind signing (use for other purposes is insecure |
||
| 39 | // when also using it for blind signatures) |
||
| 40 | func BlindSign(key *rsa.PrivateKey, hashed []byte) ([]byte, error) { |
||
| 41 | bitlen := key.PublicKey.N.BitLen() |
||
| 42 | if len(hashed)*8 > bitlen { |
||
| 43 | return nil, rsa.ErrMessageTooLong |
||
| 44 | } |
||
| 45 | |||
| 46 | c := new(big.Int).SetBytes(hashed) |
||
| 47 | m, err := decryptAndCheck(rand.Reader, key, c) |
||
| 48 | if err != nil { |
||
| 49 | return nil, err |
||
| 50 | } |
||
| 51 | |||
| 52 | return m.Bytes(), nil |
||
| 53 | } |
||
| 54 | |||
| 55 | // Unblind unblinds the blind signature. |
||
| 56 | // |
||
| 57 | // Given the Public Key of the signing entity, the blind signature, and the unblinding factor (obtained from `Blind()`), recover a new |
||
| 58 | // signature that will validate against the original hashed message. |
||
| 59 | func Unblind(pub *rsa.PublicKey, blindedSig, unblinder []byte) []byte { |
||
| 60 | m := new(big.Int).SetBytes(blindedSig) |
||
| 61 | unblinderBig := new(big.Int).SetBytes(unblinder) |
||
| 62 | m.Mul(m, unblinderBig) |
||
| 63 | m.Mod(m, pub.N) |
||
| 64 | return m.Bytes() |
||
| 65 | } |
||
| 66 | |||
| 67 | // VerifyBlindSignature verifies an unblinded blind signature. |
||
| 68 | // |
||
| 69 | // Verify that the unblinded signature properly signs the non-blinded (original) hashed message |
||
| 70 | func VerifyBlindSignature(pub *rsa.PublicKey, hashed, sig []byte) error { |
||
| 71 | m := new(big.Int).SetBytes(hashed) |
||
| 72 | bigSig := new(big.Int).SetBytes(sig) |
||
| 73 | |||
| 74 | c := encrypt(new(big.Int), pub, bigSig) |
||
| 75 | |||
| 76 | if subtle.ConstantTimeCompare(m.Bytes(), c.Bytes()) == 1 { |
||
| 77 | return nil |
||
| 78 | } else { |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 79 | return rsa.ErrVerification |
||
| 80 | } |
||
| 81 | } |
||
| 82 | |||
| 83 | // Adapted from from crypto/rsa decrypt |
||
| 84 | func blind(random io.Reader, key *rsa.PublicKey, c *big.Int) (blinded, unblinder *big.Int, err error) { |
||
| 85 | // Blinding enabled. Blinding involves multiplying c by r^e. |
||
| 86 | // Then the decryption operation performs (m^e * r^e)^d mod n |
||
| 87 | // which equals mr mod n. The factor of r can then be removed |
||
| 88 | // by multiplying by the multiplicative inverse of r. |
||
| 89 | |||
| 90 | var r *big.Int |
||
| 91 | |||
| 92 | for { |
||
| 93 | r, err = rand.Int(random, key.N) |
||
| 94 | if err != nil { |
||
| 95 | return |
||
| 96 | } |
||
| 97 | if r.Cmp(bigZero) == 0 { |
||
| 98 | r = bigOne |
||
| 99 | } |
||
| 100 | ir, ok := modInverse(r, key.N) |
||
| 101 | |||
| 102 | if ok { |
||
| 103 | bigE := big.NewInt(int64(key.E)) |
||
| 104 | rpowe := new(big.Int).Exp(r, bigE, key.N) |
||
| 105 | cCopy := new(big.Int).Set(c) |
||
| 106 | cCopy.Mul(cCopy, rpowe) |
||
| 107 | cCopy.Mod(cCopy, key.N) |
||
| 108 | return cCopy, ir, nil |
||
| 109 | } |
||
| 110 | } |
||
| 111 | } |
||
| 112 |