How to properly write JVM AES/CFB8 Encryption in Go - go

I wrote a little test in Kotlin to encrypt some text "Hello" using a Cipher instance with the algorithm "AES/CFB8/NoPadding".
(minecraft stuff)
And I am now attempting to do the same in Go, however I am unable to produce the same result. All the different methods I have tried always produce something different.
These are the following threads/examples I've already looked through in order to get to this point.
How to use rsa key pair for AES encryption and decryprion in golang
https://play.golang.org/p/77fRvrDa4A
Decrypt in Golang what was encrypted in Python AES CFB
https://gist.github.com/temoto/5052503
AES Encryption in Golang and Decryption in Java
Different Results in Go and Pycrypto when using AES-CFB
Kotlin Code:
enum class Mode(val mode: Int)
{
ENCRYPT(Cipher.ENCRYPT_MODE),
DECRYPT(Cipher.DECRYPT_MODE),
}
fun createSecret(data: String): SecretKey
{
return SecretKeySpec(data.toByteArray(), "AES")
}
fun newCipher(mode: Mode): Cipher
{
val secret = createSecret("qwdhyte62kjneThg")
val cipher = Cipher.getInstance("AES/CFB8/NoPadding")
cipher.init(mode.mode, secret, IvParameterSpec(secret.encoded))
return cipher
}
fun runCipher(data: ByteArray, cipher: Cipher): ByteArray
{
val output = ByteArray(data.size)
cipher.update(data, 0, data.size, output)
return output
}
fun main()
{
val encrypter = newCipher(Mode.ENCRYPT)
val decrypter = newCipher(Mode.DECRYPT)
val iText = "Hello"
val eText = runCipher(iText.toByteArray(), encrypter)
val dText = runCipher(eText, decrypter)
val oText = String(dText)
println(iText)
println(Arrays.toString(eText))
println(Arrays.toString(dText))
println(oText)
}
Go Code:
func TestCipher(t *testing.T) {
secret := newSecret("qwdhyte62kjneThg")
encrypter := newCipher(secret, ENCRYPT)
decrypter := newCipher(secret, DECRYPT)
iText := "Hello"
eText := encrypter.run([]byte(iText))
dText := decrypter.run(eText)
oText := string(dText)
fmt.Printf("%s\n%v\n%v\n%s\n", iText, eText, dText, oText)
}
type Mode int
const (
ENCRYPT Mode = iota
DECRYPT
)
type secret struct {
Data []byte
}
type cipherInst struct {
Data cipher2.Block
Make cipher2.Stream
}
func newSecret(text string) *secret {
return &secret{Data: []byte(text)}
}
func newCipher(data *secret, mode Mode) *cipherInst {
cip, err := aes.NewCipher(data.Data)
if err != nil {
panic(err)
}
var stream cipher2.Stream
if mode == ENCRYPT {
stream = cipher2.NewCFBEncrypter(cip, data.Data)
} else {
stream = cipher2.NewCFBDecrypter(cip, data.Data)
}
return &cipherInst{Data: cip, Make: stream}
}
func (cipher *cipherInst) run(dataI []byte) []byte {
out := make([]byte, len(dataI))
cipher.Make.XORKeyStream(out, dataI)
return out
}
Kotlin code produces the output:
Hello
[68, -97, 26, -50, 126]
[72, 101, 108, 108, 111]
Hello
However, the Go code produces the output:
Hello
[68 97 242 158 187]
[72 101 108 108 111]
Hello
At this point, this issue has pretty much halted the progress of the project I'm working on. Any information on what I'm missing or doing wrong would be helpful.

The solution to this is to implement CFB8 manually since the built in implementation defaults to CFB128.
Implementation created by kostya and fixed by Ilmari Karonen (here).

Related

Converting JWK json into a public key golang (lestrrat-go)

I'm using JWKS format to provide from an authentication service the public key that can be used to validate tokens coming from that authentication service. However, to perform validation I need to rebuild the public key from the JWK. How can I convert it?
type JWKeys struct {
Keys []JWKey `json:"keys"`
}
type JWKey struct {
Kty string `json:"kty"`
Use string `json:"use,omitempty"`
Kid string `json:"kid,omitempty"`
Alg string `json:"alg,omitempty"`
Crv string `json:"crv,omitempty"`
X string `json:"x,omitempty"`
Y string `json:"y,omitempty"`
D string `json:"d,omitempty"`
N string `json:"n,omitempty"`
E string `json:"e,omitempty"`
K string `json:"k,omitempty"`
}
var PublicKey *rsa.PublicKey
func SetUpExternalAuth() {
res, err := http.Get("my_url")
if err != nil {
log.Fatal("Can't retrieve the key for authentication")
}
bodyBytes, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
var keys JWKeys
json.Unmarshal(bodyBytes, &keys)
//CONVERT JWK TO *rsa.PUBLICKEY???
}
UPDATE
I tried to parse the JWKs using github.com/lestrrat-go/jwx/jwk library, however I couldn't find how to continue:
set,err := jwk.Parse(bodyBytes)
key,err2 := set.Get(0)
//HOW TO CONVERT KEY INTO A *rsa.PublicKey?
At the end I've manually converted it:
if singleJWK.Kty != "RSA" {
log.Fatal("invalid key type:", singleJWK.Kty)
}
// decode the base64 bytes for n
nb, err := base64.RawURLEncoding.DecodeString(singleJWK.N)
if err != nil {
log.Fatal(err)
}
e := 0
// The default exponent is usually 65537, so just compare the
// base64 for [1,0,1] or [0,1,0,1]
if singleJWK.E == "AQAB" || singleJWK.E == "AAEAAQ" {
e = 65537
} else {
// need to decode "e" as a big-endian int
log.Fatal("need to deocde e:", singleJWK.E)
}
PublicKey = &rsa.PublicKey{
N: new(big.Int).SetBytes(nb),
E: e,
}
Understand you have a solution but as you were making the attempt using github.com/lestrrat-go/jwx/jwk here is an approach with that package (pretty much what is in the example):
package main
import (
"context"
"crypto/rsa"
"fmt"
"log"
"github.com/lestrrat-go/jwx/jwk"
)
func main() {
// Example jwk from https://www.googleapis.com/oauth2/v3/certs (but with only one cert for simplicity)
jwkJSON := `{
"keys": [
{
"kty": "RSA",
"n": "o76AudS2rsCvlz_3D47sFkpuz3NJxgLbXr1cHdmbo9xOMttPMJI97f0rHiSl9stltMi87KIOEEVQWUgMLaWQNaIZThgI1seWDAGRw59AO5sctgM1wPVZYt40fj2Qw4KT7m4RLMsZV1M5NYyXSd1lAAywM4FT25N0RLhkm3u8Hehw2Szj_2lm-rmcbDXzvjeXkodOUszFiOqzqBIS0Bv3c2zj2sytnozaG7aXa14OiUMSwJb4gmBC7I0BjPv5T85CH88VOcFDV51sO9zPJaBQnNBRUWNLh1vQUbkmspIANTzj2sN62cTSoxRhSdnjZQ9E_jraKYEW5oizE9Dtow4EvQ",
"use": "sig",
"alg": "RS256",
"e": "AQAB",
"kid": "6a8ba5652a7044121d4fedac8f14d14c54e4895b"
}
]
}
`
set, err := jwk.Parse([]byte(jwkJSON))
if err != nil {
panic(err)
}
fmt.Println(set)
for it := set.Iterate(context.Background()); it.Next(context.Background()); {
pair := it.Pair()
key := pair.Value.(jwk.Key)
var rawkey interface{} // This is the raw key, like *rsa.PrivateKey or *ecdsa.PrivateKey
if err := key.Raw(&rawkey); err != nil {
log.Printf("failed to create public key: %s", err)
return
}
// We know this is an RSA Key so...
rsa, ok := rawkey.(*rsa.PublicKey)
if !ok {
panic(fmt.Sprintf("expected ras key, got %T", rawkey))
}
// As this is a demo just dump the key to the console
fmt.Println(rsa)
}
}
I wrote a Go package exactly for this purpose: github.com/MicahParks/keyfunc
Converting to a *rsa.PublicKey
In this pacakge a JSON Web Key (JWK) looks like this Go struct. It supports both ECDSA and RSA JWK.
// JSONKey represents a raw key inside a JWKS.
type JSONKey struct {
Curve string `json:"crv"`
Exponent string `json:"e"`
ID string `json:"kid"`
Modulus string `json:"n"`
X string `json:"x"`
Y string `json:"y"`
precomputed interface{}
}
After the raw JSON message is unmarshaled into the above struct, this method converts it to an *rsa.PublicKey.
package keyfunc
import (
"crypto/rsa"
"encoding/base64"
"fmt"
"math/big"
)
const (
// rs256 represents a public cryptography key generated by a 256 bit RSA algorithm.
rs256 = "RS256"
// rs384 represents a public cryptography key generated by a 384 bit RSA algorithm.
rs384 = "RS384"
// rs512 represents a public cryptography key generated by a 512 bit RSA algorithm.
rs512 = "RS512"
// ps256 represents a public cryptography key generated by a 256 bit RSA algorithm.
ps256 = "PS256"
// ps384 represents a public cryptography key generated by a 384 bit RSA algorithm.
ps384 = "PS384"
// ps512 represents a public cryptography key generated by a 512 bit RSA algorithm.
ps512 = "PS512"
)
// RSA parses a JSONKey and turns it into an RSA public key.
func (j *JSONKey) RSA() (publicKey *rsa.PublicKey, err error) {
// Check if the key has already been computed.
if j.precomputed != nil {
return j.precomputed.(*rsa.PublicKey), nil
}
// Confirm everything needed is present.
if j.Exponent == "" || j.Modulus == "" {
return nil, fmt.Errorf("%w: rsa", ErrMissingAssets)
}
// Decode the exponent from Base64.
//
// According to RFC 7518, this is a Base64 URL unsigned integer.
// https://tools.ietf.org/html/rfc7518#section-6.3
var exponent []byte
if exponent, err = base64.RawURLEncoding.DecodeString(j.Exponent); err != nil {
return nil, err
}
// Decode the modulus from Base64.
var modulus []byte
if modulus, err = base64.RawURLEncoding.DecodeString(j.Modulus); err != nil {
return nil, err
}
// Create the RSA public key.
publicKey = &rsa.PublicKey{}
// Turn the exponent into an integer.
//
// According to RFC 7517, these numbers are in big-endian format.
// https://tools.ietf.org/html/rfc7517#appendix-A.1
publicKey.E = int(big.NewInt(0).SetBytes(exponent).Uint64())
// Turn the modulus into a *big.Int.
publicKey.N = big.NewInt(0).SetBytes(modulus)
// Keep the public key so it won't have to be computed every time.
j.precomputed = publicKey
return publicKey, nil
}
Parsing and validating a JWT from a JSON Web Key Set (JWKS).
I made this package to work with github.com/dgrijalva/jwt-go to more easily parse and validate JWTs with the most popular package.
Using your example URL, my_url, here's an example of how to parse and validate JWTs.
package main
import (
"log"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/MicahParks/keyfunc"
)
func main() {
// Get the JWKS URL.
jwksURL := "my_url"
// Create the keyfunc options. Refresh the JWKS every hour and log errors.
refreshInterval := time.Hour
options := keyfunc.Options{
RefreshInterval: &refreshInterval,
RefreshErrorHandler: func(err error) {
log.Printf("There was an error with the jwt.KeyFunc\nError: %s", err.Error())
},
}
// Create the JWKS from the resource at the given URL.
jwks, err := keyfunc.Get(jwksURL, options)
if err != nil {
log.Fatalf("Failed to create JWKS from resource at the given URL.\nError: %s", err.Error())
}
// Get a JWT to parse.
jwtB64 := "eyJhbGciOiJQUzM4NCIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMeDFGbWF5UDJZQnR4YXFTMVNLSlJKR2lYUktudzJvdjVXbVlJTUctQkxFIn0.eyJleHAiOjE2MTU0MDY5ODIsImlhdCI6MTYxNTQwNjkyMiwianRpIjoiMGY2NGJjYTktYjU4OC00MWFhLWFkNDEtMmFmZDM2OGRmNTFkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.Rxrq41AxbWKIQHWv-Tkb7rqwel3sKT_R_AGvn9mPIHqhw1m7nsQWcL9t2a_8MI2hCwgWtYdgTF1xxBNmb2IW3CZkML5nGfcRrFvNaBHd3UQEqbFKZgnIX29h5VoxekyiwFaGD-0RXL83jF7k39hytEzTatwoVjZ-frga0KFl-nLce3OwncRXVCGmxoFzUsyu9TQFS2Mm_p0AMX1y1MAX1JmLC3WFhH3BohhRqpzBtjSfs_f46nE1-HKjqZ1ERrAc2fmiVJjmG7sT702JRuuzrgUpHlMy2juBG4DkVcMlj4neJUmCD1vZyZBRggfaIxNkwUhHtmS2Cp9tOcwNu47tSg"
// Parse the JWT.
token, err := jwt.Parse(jwtB64, jwks.KeyFunc)
if err != nil {
log.Fatalf("Failed to parse the JWT.\nError: %s", err.Error())
}
// Check if the token is valid.
if !token.Valid {
log.Fatalf("The token is not valid.")
}
log.Println("The token is valid.")
}

How to generate the ECDSA public key from its private key?

The following site is frequently referenced and, I assume, accurate:
https://gobittest.appspot.com/Address
I'm trying to repro these steps in Golang but failing at the first step :-(
Is someone able to provide me with a Golang snippet that, given a ECDSA private key, returns the public key? I think I may specifically mean the private key exponent and public key exponent per the above site's examples.
i.e. given e.g. a randomly-generated (hex-encoded) private key (exponent?) E83385AF76B2B1997326B567461FB73DD9C27EAB9E1E86D26779F4650C5F2B75 returns the public key 04369D83469A66920F31E4CF3BD92CB0BC20C6E88CE010DFA43E5F08BC49D11DA87970D4703B3ADBC9A140B4AD03A0797A6DE2D377C80C369FE76A0F45A7A39D3F
I've found many (relevant) results:
https://crypto.stackexchange.com/questions/5756/how-to-generate-a-public-key-from-a-private-ecdsa-key
But none that includes a definitive example.
Go's crypto/ecdsa module allows keys to generated and includes a Public function on the type but this returns the PublicKey property.
Alternative ways that start from a private key appear to require going through a PEM-encoded (including a DER-encoded ASN) form of the key which feels circuitous (and I would need to construct).
Update:
See the answers below: andrew-w-phillips# and kelsnare# provided the (same|correct) solution. Thanks to both of them!
For posterity, Bitcoin (and Ethereum) use an elliptic curve defined by secp256k1. The following code from andrew-w-phillips# and kelsnare# using Ethereum's implementation of this curve, works:
import (
"crypto/ecdsa"
"crypto/elliptic"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)
func Public(privateKey string) (publicKey string) {
var e ecdsa.PrivateKey
e.D, _ = new(big.Int).SetString(privateKey, 16)
e.PublicKey.Curve = secp256k1.S256()
e.PublicKey.X, e.PublicKey.Y = e.PublicKey.Curve.ScalarBaseMult(e.D.Bytes())
return fmt.Sprintf("%x", elliptic.Marshal(secp256k1.S256(), e.X, e.Y))
}
func main() {
privateKey := "E83385AF76B2B1997326B567461FB73DD9C27EAB9E1E86D26779F4650C5F2B75"
log.Println(strings.ToUpper(Public(privateKey)))
}
yields:
04369D83469A66920F31E4CF3BD92CB0BC20C6E88CE010DFA43E5F08BC49D11DA87970D4703B3ADBC9A140B4AD03A0797A6DE2D377C80C369FE76A0F45A7A39D3F
After reading the answer by Andrew W. Phillips and a little help from https://github.com/bitherhq/go-bither/tree/release/1.7/crypto
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"log"
"math/big"
)
func PubBytes(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(elliptic.P256(), pub.X, pub.Y)
}
func toECDSAFromHex(hexString string) (*ecdsa.PrivateKey, error) {
pk := new(ecdsa.PrivateKey)
pk.D, _ = new(big.Int).SetString(hexString, 16)
pk.PublicKey.Curve = elliptic.P256()
pk.PublicKey.X, pk.PublicKey.Y = pk.PublicKey.Curve.ScalarBaseMult(pk.D.Bytes())
return pk, nil
}
func main() {
pHex := "E83385AF76B2B1997326B567461FB73DD9C27EAB9E1E86D26779F4650C5F2B75"
pk, err := toECDSAFromHex(pHex)
if err != nil {
log.Fatal(err.Error())
}
fmt.Printf("Generated Public Key: %x\n", PubBytes(&pk.PublicKey))
hash := []byte("Hello Gopher!")
fmt.Printf("\nSigning...\n\n")
r, s, err := ecdsa.Sign(rand.Reader, pk, hash)
if err != nil {
log.Fatal(err.Error())
}
fmt.Printf("\nVerifying..\n\n")
if ecdsa.Verify(&pk.PublicKey, hash, r, s) {
fmt.Println("Success!!")
} else {
fmt.Println("Failure!!")
}
}
// Output
// Generated Public Key: 04265a5015c0cfd960e5a41f35e0a87874c1d8a28289d0d6ef6ac521ad49c3d80a8a7019ceef189819f066a947ad5726db1a4fe70a3208954c46b0e60f2bf7809c
//
// Signing...
//
//
// Verifying..
//
// Success!!
======== ORIGINAL ANSWER ===========
Dunno much of crypto but crypto/elliptic has a Marshal function
So once you have a *PrivateKey maybe the below will work
import (
"crypto/elliptic"
"crypto/ecdsa"
)
var privKey *ecdsa.PrivateKey
func main() {
// some init to privKey
pk := privKey.PublicKey()
keybuf := elliptic.Marshal(pk.Curve, pk.X, pk.Y)
log.Printf("Key: %s\n", string(keybuf))
}
I'm shooting completely in the dark with this. Hope it helps
I haven't got that low-level but maybe something like this:
var pri ecdsa.PrivateKey
pri.D, _ = new(big.Int).SetString("E83385AF76B2B1997326B567461FB73DD9C27EAB9E1E86D26779F4650C5F2B75",16)
pri.PublicKey.Curve = elliptic.P256()
pri.PublicKey.X, pri.PublicKey.Y = pri.PublicKey.Curve.ScalarBaseMult(pri.D.Bytes())

Golang Parsing of ProtoBuf

I'm new to Golang and I am trying to write an home automation framework in Golang, using the Micro framework and Protobuf framework.
I am currently having a hard time trying to implement a simple registry type service.
An example of the problem I am having is that I have the following, I want to be able to get a list of devices, provided a client does a GET request to http://localhost:8080/view/devices
I have the following protobuf definition:
syntax = "proto3";
service DRegistry {
rpc View(ViewRequest) returns (DeviceRegistry) {}
}
message DeviceRegistry {
repeated Device devices = 1;
}
message ViewRequest {
string Alias = 1;
}
message Device {
string Alias = 1;
string HWAddress = 2;
string WakeUpMethod = 3;
repeated string BoundServices = 4;
}
Then in my service defination I have the following:
package main
import (
"log"
micro "github.com/micro/go-micro"
proto "github.com/srizzling/gotham/proto/device"
"golang.org/x/net/context"
)
// DRegistry stands for Device Registry and is how devices register to Gotham.
type DRegistry struct{}
var devices map[string]proto.Device
func (g *DRegistry) View(ctx context.Context, req *proto.ViewRequest, rsp *proto.DeviceRegistry) error {
filter := req.Alias
devices, err := filterDevices(filter)
rsp.Devices = devices
}
func filterDevices(filter string) (*[]proto.Device, error) {
// Currently only supports listing a single service for now
// TODO: expand filter to be more consise
filteredDevices := make([]proto.Device, 0, len(devices))
for _, e := range devices {
for _, f := range e.BoundServices {
if f == filter {
filteredDevices = append(filteredDevices, e)
}
}
}
return &filteredDevices, nil
}
func main() {
service := micro.NewService(
micro.Name("DRegistry"),
)
proto.RegisterDRegistryHandler(service.Server(), new(DRegistry))
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
The problem I am having is that my IDE (Visual Studio Code) is complianing that I cannot use devices (type *[]device.Device) as type []*device.Device in assignment which is confusing.
TLDR: How do I assign a collection of proto.Devices to the proto.DeviceRegistry?
func filterDevices(filter string) ([]*proto.Device, error) {
// Currently only supports listing a single service for now
// TODO: expand filter to be more consise
filteredDevices := make([]*proto.Device, 0, len(devices))
for _, e := range devices {
for _, f := range e.BoundServices {
if f == filter {
filteredDevices = append(filteredDevices, &e)
}
}
}
return filteredDevices, nil
}
There is a difference between a slice of pointers ([]*) and a pointer to a slice (*[]). You are returning a pointer to slice, whereas what you want is a slice of pointers. We can solve this by:
Updating your filterDevices signature to return a slice of pointers
Updating your make call to make a slice of pointers
Taking the address of e in your call to append (we want a slice of pointers to devices)
Not returning the address of the slice

golang - marshal PKCS8 private key?

Is there a way to marshal a PKCS8 private key in go 1.5?
e.g. something similar to or starting from x509.MarshalPKCS1PrivateKey?
Funny enough, there are no standard function to do that, but here is a custom solution:
type pkcs8Key struct {
Version int
PrivateKeyAlgorithm []asn1.ObjectIdentifier
PrivateKey []byte
}
func rsa2pkcs8(key *rsa.PrivateKey) ([]byte, error) {
var pkey pkcs8Key
pkey.Version = 0
pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
pkey.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
pkey.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
return asn1.Marshal(pkey)
}
Since the above answer was written, go 1.10 has been released with a x509.MarshalPKCS8PrivateKey method.

Cannot sign a valid gpg key using golang's openpgp packet

I want to sign a public key from ascii armor with a private key in go language.For that I developed following code but the problem is when I check the signature in gpg --check-sigs the signature created by code is shown as "bad Signature".Please Help as I cant figure out any way of solving it.I have already postd on golang-nuts.I am just learning golang for my college project and I am stuck here,Please help.
// signer
package main
import (
"bytes"
"code.google.com/p/go.crypto/openpgp"
"code.google.com/p/go.crypto/openpgp/armor"
"code.google.com/p/go.crypto/openpgp/packet"
"fmt"
)
// This function takes asciiarmored private key which will sign the public key
//Public key is also ascii armored,pripwd is password of private key in string
//This function will return ascii armored signed public key i.e. (pubkey+sign by prikey)
func SignPubKeyPKS(asciiPub string, asciiPri string, pripwd string) (asciiSignedKey string) {
//get Private key from armor
_, priEnt := getPri(asciiPri, pripwd) //pripwd is the password todecrypt the private key
_, pubEnt := getPub(asciiPub) //This will generate signature and add it to pubEnt
usrIdstring := ""
for _, uIds := range pubEnt.Identities {
usrIdstring = uIds.Name
}
fmt.Println(usrIdstring)
errSign := pubEnt.SignIdentity(usrIdstring, &priEnt, nil)
if errSign != nil {
fmt.Println("Signing Key ", errSign.Error())
return
}
asciiSignedKey = PubEntToAsciiArmor(pubEnt)
return
}
//get packet.PublicKey and openpgp.Entity of Public Key from ascii armor
func getPub(asciiPub string) (pubKey packet.PublicKey, retEntity openpgp.Entity) {
read1 := bytes.NewReader([]byte(asciiPub))
entityList, errReadArm := openpgp.ReadArmoredKeyRing(read1)
if errReadArm != nil {
fmt.Println("Reading Pubkey ", errReadArm.Error())
return
}
for _, pubKeyEntity := range entityList {
if pubKeyEntity.PrimaryKey != nil {
pubKey = *pubKeyEntity.PrimaryKey
retEntity = *pubKeyEntity
}
}
return
}
//get packet.PrivateKEy and openpgp.Entity of Private Key from ascii armor
func getPri(asciiPri string, pripwd string) (priKey packet.PrivateKey, priEnt openpgp.Entity) {
read1 := bytes.NewReader([]byte(asciiPri))
entityList, errReadArm := openpgp.ReadArmoredKeyRing(read1)
if errReadArm != nil {
fmt.Println("Reading PriKey ", errReadArm.Error())
return
}
for _, can_pri := range entityList {
smPr := can_pri.PrivateKey
retEntity := can_pri
if smPr == nil {
fmt.Println("No Private Key")
return
}
priKey = *smPr
errDecr := priKey.Decrypt([]byte(pripwd))
if errDecr != nil {
fmt.Println("Decrypting ", errDecr.Error())
return
}
retEntity.PrivateKey = &priKey
priEnt = *retEntity
}
return
}
//Create ASscii Armor from openpgp.Entity
func PubEntToAsciiArmor(pubEnt openpgp.Entity) (asciiEntity string) {
gotWriter := bytes.NewBuffer(nil)
wr, errEncode := armor.Encode(gotWriter, openpgp.PublicKeyType, nil)
if errEncode != nil {
fmt.Println("Encoding Armor ", errEncode.Error())
return
}
errSerial := pubEnt.Serialize(wr)
if errSerial != nil {
fmt.Println("Serializing PubKey ", errSerial.Error())
}
errClosing := wr.Close()
if errClosing != nil {
fmt.Println("Closing writer ", errClosing.Error())
}
asciiEntity = gotWriter.String()
return
}
The code looks roughly ok, except that it really should be stricter with error checking. Panicking on error is better then no error checking at all (because it will usually segfault sometimes later).
The problem is that the implementation of Signature.SignUserId() inside code.google.com/p/go.crypto/openpgp is wrong. It is using the algorithm that signs a key (which is use to certify that the subkey belongs to the primary key) instead of the algorithm that signs a user id.
In addition, while exploring this I realized that PublicKey.VerifyUserIdSignature() is implemented in such a way that it only works for self-signed user ids, because it doesn't use the right public key in the hash.
Bug report, with patch https://code.google.com/p/go/issues/detail?id=7371

Resources