-
Notifications
You must be signed in to change notification settings - Fork 0
/
challenge46.go
73 lines (62 loc) · 2.03 KB
/
challenge46.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package set6
import (
"bytes"
"fmt"
"math/big"
"github.com/alokmenghrajani/go-cryptopals/bigutils"
"github.com/alokmenghrajani/go-cryptopals/cryptography/rsa"
"github.com/alokmenghrajani/go-cryptopals/encoding/base64"
"github.com/alokmenghrajani/go-cryptopals/rng"
"github.com/alokmenghrajani/go-cryptopals/utils"
)
func Challenge46(rng *rng.Rng) {
utils.PrintTitle(6, 46)
pubKey, privKey := rsa.GenerateKeyPair(rng, 1024)
plaintext := base64.ToByteSlice("VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ==")
ciphertext := pubKey.Encrypt(plaintext)
// A naive implementation of the binary search will accumulate rounding errors and the
// last byte will end up being incorrect. It is therefore more accurate to keep track
// of the bounds by tracking the numerator/denominator.
lowerBound := big.NewInt(0)
upperBound := &big.Int{}
upperBound.Set(pubKey.N)
denominator := big.NewInt(1)
c := bigutils.FromBytes(ciphertext)
facTwo := &big.Int{}
facTwo.Exp(bigutils.Two, pubKey.E, pubKey.N)
delta := &big.Int{}
result := &big.Int{}
previousLen := -1
for {
c.Mul(c, facTwo)
delta.Sub(upperBound, lowerBound)
if delta.Cmp(denominator) == -1 {
break
}
lowerBound.Mul(lowerBound, bigutils.Two)
upperBound.Mul(upperBound, bigutils.Two)
denominator.Mul(denominator, bigutils.Two)
if parityOracle(privKey, c.Bytes()) {
lowerBound.Add(lowerBound, delta)
result.Div(lowerBound, denominator)
} else {
upperBound.Sub(upperBound, delta)
result.Div(upperBound, denominator)
}
buf := result.Bytes()
if len(buf) == previousLen && buf[0] >= 'A' && buf[0] <= 'z' {
fmt.Printf("%q\n", string(result.Bytes()))
}
previousLen = len(buf)
}
result.Div(upperBound, denominator)
fmt.Printf("plaintext: %s\n", string(result.Bytes()))
if !bytes.Equal(result.Bytes(), plaintext) {
panic("failed to decrypt")
}
fmt.Println()
}
func parityOracle(privKey rsa.PrivKey, ciphertext []byte) bool {
plaintext := privKey.Decrypt(ciphertext)
return plaintext[len(plaintext)-1]&0x1 == 1
}