Created
August 18, 2014 00:13
-
-
Save nickvanw/96f739a68f36c0b29b9c to your computer and use it in GitHub Desktop.
FiSH DH1080 in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/cipher" | |
"crypto/rand" | |
"crypto/sha1" | |
"encoding/base64" | |
"errors" | |
"fmt" | |
"math/big" | |
"strings" | |
"code.google.com/p/go.crypto/blowfish" | |
"github.com/monnand/dhkx" | |
) | |
const DH1080_PRIME = "FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B" | |
func main() { | |
alice := DH1080_Init() | |
bob := DH1080_Init() | |
aliceData, err := alice.Pack() | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
err = bob.Unpack(aliceData) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
bobData, err := bob.Pack() | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
err = alice.Unpack(bobData) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
bobSecret, err := bob.GetSecret() | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
aliceSecret, err := alice.GetSecret() | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
testPhrase := blowfishChecksizeAndPad([]byte("This is a test")) | |
fmt.Println("Encoding:", string(testPhrase)) | |
enc := blowfishEncrypt(testPhrase, []byte(bobSecret)) | |
fmt.Println("Encoded Value:", enc) | |
dec := blowfishDecrypt(enc, []byte(aliceSecret)) | |
fmt.Println("Decoded:", string(dec)) | |
} | |
type DH1080 struct { | |
Public []byte | |
Private *dhkx.DHKey | |
State int | |
Secret *dhkx.DHKey | |
Group *dhkx.DHGroup | |
} | |
func DH1080_Init() *DH1080 { | |
DH1080Ctx := &DH1080{} | |
p, _ := new(big.Int).SetString(DH1080_PRIME, 16) | |
group := dhkx.CreateGroup(p, new(big.Int).SetInt64(2)) | |
priv, _ := group.GeneratePrivateKey(rand.Reader) | |
pub := priv.Bytes() | |
DH1080Ctx.Public = pub | |
DH1080Ctx.Private = priv | |
DH1080Ctx.State = 0 | |
DH1080Ctx.Group = group | |
return DH1080Ctx | |
} | |
func (dh *DH1080) Pack() (string, error) { | |
var cmd string | |
if dh.State == 0 { | |
dh.State = 1 | |
cmd = "DH1080_INIT " | |
} else { | |
cmd = "DH1080_FINISH " | |
} | |
data, err := DH1080_Base64Encode(dh.Public) | |
if err != nil { | |
return "", err | |
} | |
return cmd + data, nil | |
} | |
func (dh *DH1080) GetSecret() (string, error) { | |
if dh.Secret == nil { | |
return "", errors.New("No secret to encode") | |
} | |
data := []byte(dh.Secret.String()) | |
hasher := sha1.New() | |
hasher.Write(data) | |
return DH1080_Base64Encode(hasher.Sum(nil)) | |
} | |
func (dh *DH1080) Unpack(msg string) error { | |
if !strings.HasPrefix(msg, "DH1080_") { | |
return errors.New("Invalid Message") | |
} | |
data := strings.Split(msg, " ") | |
keyData := data[1] | |
decodedKeyData, _ := DH1080_Base64Decode(keyData) | |
otherPubKey := dhkx.NewPublicKey(decodedKeyData) | |
key, err := dh.Group.ComputeKey(otherPubKey, dh.Private) | |
if err != nil { | |
return err | |
} | |
dh.Secret = key | |
return nil | |
} | |
func DH1080_Base64Encode(data []byte) (string, error) { | |
if len(data) < 1 { | |
return "", errors.New("Zero Length String") | |
} | |
encodedString := base64.StdEncoding.EncodeToString(data) | |
if !strings.Contains(encodedString, "=") { | |
encodedString += "A" | |
} else { | |
encodedString = strings.TrimRight(encodedString, "=") | |
} | |
return encodedString, nil | |
} | |
func DH1080_Base64Decode(data string) ([]byte, error) { | |
if len(data)%4 == 1 && data[len(data)-1] == 'A' { | |
return base64.StdEncoding.DecodeString(string(data[:len(data)-1])) | |
} | |
data = data + strings.Repeat("=", (4-(len(data)%4))) | |
return base64.StdEncoding.DecodeString(data) | |
} | |
func blowfishChecksizeAndPad(pt []byte) []byte { | |
// calculate modulus of plaintext to blowfish's cipher block size | |
// if result is not 0, then we need to pad | |
modulus := len(pt) % blowfish.BlockSize | |
if modulus != 0 { | |
// how many bytes do we need to pad to make pt to be a multiple of blowfish's block size? | |
padlen := blowfish.BlockSize - modulus | |
// let's add the required padding | |
for i := 0; i < padlen; i++ { | |
// add the pad, one at a time | |
pt = append(pt, 0) | |
} | |
} | |
// return the whole-multiple-of-blowfish.BlockSize-sized plaintext to the calling function | |
return pt | |
} | |
func blowfishDecrypt(et, key []byte) []byte { | |
// create the cipher | |
dcipher, err := blowfish.NewCipher(key) | |
if err != nil { | |
// fix this. its okay for this tester program, but... | |
panic(err) | |
} | |
// make initialisation vector to be the first 8 bytes of ciphertext. | |
// see related note in blowfishEncrypt() | |
div := et[:blowfish.BlockSize] | |
// check last slice of encrypted text, if it's not a modulus of cipher block size, we're in trouble | |
decrypted := et[blowfish.BlockSize:] | |
if len(decrypted)%blowfish.BlockSize != 0 { | |
panic("decrypted is not a multiple of blowfish.BlockSize") | |
} | |
// ok, we're good... create the decrypter | |
dcbc := cipher.NewCBCDecrypter(dcipher, div) | |
// decrypt! | |
dcbc.CryptBlocks(decrypted, decrypted) | |
return decrypted | |
} | |
func blowfishEncrypt(ppt, key []byte) []byte { | |
// create the cipher | |
ecipher, err := blowfish.NewCipher(key) | |
if err != nil { | |
// fix this. its okay for this tester program, but .... | |
panic(err) | |
} | |
// make ciphertext big enough to store len(ppt)+blowfish.BlockSize | |
ciphertext := make([]byte, blowfish.BlockSize+len(ppt)) | |
// make initialisation vector to be the first 8 bytes of ciphertext. you | |
// wouldn't do this normally/in real code, but this IS example code! :) | |
eiv := ciphertext[:blowfish.BlockSize] | |
// create the encrypter | |
ecbc := cipher.NewCBCEncrypter(ecipher, eiv) | |
// encrypt the blocks, because block cipher | |
ecbc.CryptBlocks(ciphertext[blowfish.BlockSize:], ppt) | |
// return ciphertext to calling function | |
return ciphertext | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment