Skip to content

Instantly share code, notes, and snippets.

@dimchansky
Created July 23, 2018 07:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimchansky/2d7709c77517b28cdcd8d20a5b1188a3 to your computer and use it in GitHub Desktop.
Save dimchansky/2d7709c77517b28cdcd8d20a5b1188a3 to your computer and use it in GitHub Desktop.
Chosen Ciphertext Attack against RSA
package main
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"math/big"
"os"
)
func main() {
const size = 128 // using small key size for simplicity, but it works for any key size
// victim generates RSA keys
priv, err := rsa.GenerateKey(rand.Reader, size)
if err != nil {
fmt.Printf("GenerateKey: %v\n", err)
os.Exit(1)
}
pub := &priv.PublicKey
// message to encrypt
m := big.NewInt(42)
fmt.Printf("message: %v\n", m)
// victim encrypts the message
me := encrypt(pub, m)
fmt.Printf("encrypted message: %v\n", me)
// victim tests message decryption
md := decrypt(priv, me)
fmt.Printf("test decryption: %v\n", md)
// hacker listening in on victim's communications, manages to collect a ciphertext message.
// hacker wants to be able to read the message, to recover message he computes evil message
evMsg, t := prepareEvilMessage(pub, me)
fmt.Printf("evil message: %v\n", evMsg)
// hacker gets victim to sign evMsg with victim's private key, thereby decrypting evMsg.
// victim has never seen evMsg before, victim signs the message and send it back to hacker:
u := decrypt(priv, evMsg) // victim has to sign the message, not the hash of the message
fmt.Printf("signed evil message: %v\n", u)
// hacker decrypts the message
c := new(big.Int).Mod(new(big.Int).Mul(t, u), pub.N)
fmt.Printf("hacked message: %v\n", c)
// Moral: Never use RSA to sign a random document presented to you by a
// stranger. Always use a one-way hash function first.
}
func prepareEvilMessage(pub *rsa.PublicKey, m *big.Int) (*big.Int, *big.Int) {
r, _ := rand.Int(rand.Reader, pub.N)
t := new(big.Int).ModInverse(r, pub.N)
x := encrypt(pub, r)
evMsg := new(big.Int).Mod(new(big.Int).Mul(x, m), pub.N)
return evMsg, t
}
func encrypt(pub *rsa.PublicKey, m *big.Int) *big.Int {
return new(big.Int).Exp(m, big.NewInt(int64(pub.E)), pub.N)
}
func decrypt(priv *rsa.PrivateKey, m *big.Int) *big.Int {
return new(big.Int).Exp(m, priv.D, priv.N)
}
@dimchansky
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment