copied the project from https://bitbucket.org/ustraca/crypto
This commit is contained in:
1 parent
f464823c87
commit
3625be471c
4 files changed
+322
No files matched your search
@@ -0,0 +1,4 @@
|
||||
---
|
||||
language: go
|
||||
go:
|
||||
- tip
|
||||
@@ -2,3 +2,29 @@ elgamal
|
||||
=======
|
||||
|
||||
Pure elgamal cryptosystem implemented in Go
|
||||
|
||||
[](https://travis-ci.org/didiercrunch/elgamal/)
|
||||
|
||||
|
||||
#### introduction
|
||||
|
||||
Implementation of the El Gamal cryptosystem. See
|
||||
http://en.wikipedia.org/wiki/ElGamal_encryption for an introduction.
|
||||
|
||||
The difference between this implementation and the one at golang.org/x/crypto/openpgp/elgamal
|
||||
is the use of absolutly no padding here.
|
||||
|
||||
The absance of padding is cool if you want to encrypt numbers and need to make algebra
|
||||
on the cypher texts. The use of padding is needed when you encrypt data and you
|
||||
do not want to allow algebraic operations on the cypher texts.
|
||||
|
||||
Another important feature of the library is the ease of serilisation of all
|
||||
the structs in JSON and BSON.
|
||||
|
||||
|
||||
#### caveat
|
||||
|
||||
As any cryptographic library, if you use it, you need to *trust* it. Unfortunatly,
|
||||
this library as not been verified by a third party. There might be some bugs and
|
||||
vulnerabilities. If you find one, please fill a bug.
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package elgamal
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
// PublicKey represents an ElGamal public key.
|
||||
type PublicKey struct {
|
||||
G, P, Y *big.Int
|
||||
}
|
||||
|
||||
func (pub *PublicKey) Encrypt(msg []byte, random io.Reader) (cypher *Cypher, err error) {
|
||||
m := new(big.Int).SetBytes(msg)
|
||||
|
||||
k, err := rand.Int(random, pub.P)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c1 := new(big.Int).Exp(pub.G, k, pub.P)
|
||||
s := new(big.Int).Exp(pub.Y, k, pub.P)
|
||||
|
||||
c2 := s.Mul(s, m)
|
||||
c2.Mod(c2, pub.P)
|
||||
cypher = &Cypher{c1, c2, pub.P}
|
||||
return
|
||||
}
|
||||
|
||||
func (this *PublicKey) GetBSON() (interface{}, error) {
|
||||
return bson.D{
|
||||
{"g", fmt.Sprintf("%x", this.G)},
|
||||
{"p", fmt.Sprintf("%x", this.P)},
|
||||
{"y", fmt.Sprintf("%x", this.Y)},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PrivateKey represents an ElGamal private key.
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
X *big.Int
|
||||
}
|
||||
|
||||
func (this *PrivateKey) GetBSON() (interface{}, error) {
|
||||
return bson.D{
|
||||
{"x", fmt.Sprintf("%x", this.X)},
|
||||
{"g", fmt.Sprintf("%x", this.G)},
|
||||
{"p", fmt.Sprintf("%x", this.P)},
|
||||
{"y", fmt.Sprintf("%x", this.Y)},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (priv *PrivateKey) Decrypt(cypher *Cypher) (msg []byte) {
|
||||
s := new(big.Int).Exp(cypher.C1, priv.X, priv.P)
|
||||
s.ModInverse(s, priv.P)
|
||||
s.Mul(s, cypher.C2)
|
||||
s.Mod(s, priv.P)
|
||||
em := s.Bytes()
|
||||
return em
|
||||
}
|
||||
|
||||
type Cypher struct {
|
||||
C1, C2, P *big.Int
|
||||
}
|
||||
|
||||
func (this *Cypher) GetBSON() (interface{}, error) {
|
||||
return bson.D{
|
||||
{"c1", fmt.Sprintf("%x", this.C1)},
|
||||
{"c2", fmt.Sprintf("%x", this.C2)},
|
||||
{"p", fmt.Sprintf("%x", this.P)},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *Cypher) Mul(cypher1, cypher2 *Cypher) *Cypher {
|
||||
this.C1 = new(big.Int).Mod(new(big.Int).Mul(cypher1.C1, cypher2.C1), cypher1.P)
|
||||
this.C2 = new(big.Int).Mod(new(big.Int).Mul(cypher1.C2, cypher2.C2), cypher1.P)
|
||||
this.P = cypher1.P
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Cypher) ToJSON() map[string]string {
|
||||
return map[string]string{
|
||||
"C1": fmt.Sprintf("%x", this.C1),
|
||||
"C2": fmt.Sprintf("%x", this.C2),
|
||||
"P": fmt.Sprintf("%x", this.P),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Cypher) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(this.ToJSON())
|
||||
}
|
||||
|
||||
func (this *Cypher) UnmarshalJSON(bytes []byte) error {
|
||||
m := make(map[string]string)
|
||||
err := json.Unmarshal(bytes, &m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.FromJSON(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Cypher) FromJSON(json map[string]string) (*Cypher, error) {
|
||||
var err error
|
||||
this.C1, err = fromHex(json["C1"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
this.C2, err = fromHex(json["C2"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
this.P, err = fromHex(json["P"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this, err
|
||||
}
|
||||
|
||||
func fromHex(hex string) (*big.Int, error) {
|
||||
n, err := new(big.Int).SetString(hex, 16)
|
||||
if !err {
|
||||
msg := fmt.Sprintf("Cannot convert %s to int as hexadecimal", hex)
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package elgamal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"bitbucket.org/ustraca/crypto"
|
||||
)
|
||||
|
||||
// This is the 1024-bit MODP group from RFC 5114, section 2.1:
|
||||
const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D" +
|
||||
"23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACC" +
|
||||
"BDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC" +
|
||||
"8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
|
||||
|
||||
const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CF" +
|
||||
"F14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F" +
|
||||
"4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D" +
|
||||
"18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
|
||||
|
||||
func fromSafeHex(s string) *big.Int {
|
||||
ret, err := crypto.FromHex(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
priv := &PrivateKey{
|
||||
PublicKey: PublicKey{
|
||||
G: fromSafeHex(generatorHex),
|
||||
|
||||
P: fromSafeHex(primeHex),
|
||||
},
|
||||
X: fromSafeHex("42"),
|
||||
}
|
||||
priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
|
||||
|
||||
message := []byte("hello world")
|
||||
cypher, err := priv.PublicKey.Encrypt(message, rand.Reader)
|
||||
if err != nil {
|
||||
t.Errorf("error encrypting: %s", err)
|
||||
}
|
||||
message2 := priv.Decrypt(cypher)
|
||||
if !bytes.Equal(message2, message) {
|
||||
t.Errorf("decryption failed, got: '%x', want: '%x'", message2, message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptDecryptWithSmallNumbers(t *testing.T) {
|
||||
priv := &PrivateKey{
|
||||
PublicKey: PublicKey{
|
||||
G: big.NewInt(33),
|
||||
P: big.NewInt(71),
|
||||
},
|
||||
X: big.NewInt(42),
|
||||
}
|
||||
priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
|
||||
|
||||
message := big.NewInt(15).Bytes()
|
||||
cypher, err := priv.PublicKey.Encrypt(message, rand.Reader)
|
||||
if err != nil {
|
||||
t.Errorf("error encrypting: %s", err)
|
||||
}
|
||||
message2 := priv.Decrypt(cypher)
|
||||
if !bytes.Equal(message2, message) {
|
||||
t.Errorf("decryption failed, got: %x, want: %x", message2, message)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHomomorphicProperties(t *testing.T) {
|
||||
priv := PrivateKey{
|
||||
PublicKey: PublicKey{
|
||||
G: big.NewInt(33),
|
||||
P: big.NewInt(71),
|
||||
},
|
||||
X: big.NewInt(42),
|
||||
}
|
||||
priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
|
||||
|
||||
message1 := big.NewInt(11).Bytes()
|
||||
cypher1, _ := priv.PublicKey.Encrypt(message1, rand.Reader)
|
||||
|
||||
message2 := big.NewInt(12).Bytes()
|
||||
cypher2, _ := priv.PublicKey.Encrypt(message2, rand.Reader)
|
||||
|
||||
decyphered := priv.Decrypt(new(Cypher).Mul(cypher1, cypher2))
|
||||
expected := big.NewInt((12 * 11) % 71).Bytes()
|
||||
if !bytes.Equal(expected, decyphered) {
|
||||
t.Errorf("decryption failed, got: %x, want: %x", decyphered, expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCypherToJSON(t *testing.T) {
|
||||
cypher := &Cypher{
|
||||
C1: big.NewInt(33),
|
||||
C2: big.NewInt(99),
|
||||
P: big.NewInt(192),
|
||||
}
|
||||
exp := make(map[string]string)
|
||||
exp["C1"] = "21"
|
||||
exp["C2"] = "63"
|
||||
exp["P"] = "c0"
|
||||
|
||||
if !reflect.DeepEqual(exp, cypher.ToJSON()) {
|
||||
t.Error(exp, "is not ", cypher.ToJSON())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCypherFromJSON(t *testing.T) {
|
||||
m := make(map[string]string)
|
||||
m["C1"] = "21"
|
||||
m["C2"] = "63"
|
||||
m["P"] = "c0"
|
||||
|
||||
cypher, err := new(Cypher).FromJSON(m)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(cypher.P, big.NewInt(192)) {
|
||||
t.Error("P not okay")
|
||||
}
|
||||
if !reflect.DeepEqual(cypher.C1, big.NewInt(33)) {
|
||||
t.Error("C1 not okay")
|
||||
}
|
||||
if !reflect.DeepEqual(cypher.C2, big.NewInt(99)) {
|
||||
t.Error("C2 not okay")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMarshalling(t *testing.T) {
|
||||
cypher := &Cypher{
|
||||
C1: big.NewInt(33),
|
||||
C2: big.NewInt(99),
|
||||
P: big.NewInt(192),
|
||||
}
|
||||
s, err := cypher.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
cypher2 := new(Cypher)
|
||||
err = cypher2.UnmarshalJSON(s)
|
||||
if err != nil {
|
||||
t.Error("could not unmarshal", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cypher, cypher2) {
|
||||
t.Error("the two objects do not match!")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user