Been working for days trying to get Golang AES-CBC to CryptoJS working (or vice-versa), I fixed most of the errors but not getting decryption even though i have confirmed the key, iv, ciphertext is the same on both ends.
There must be someone who knows, there is no working example anywhere on the net for this...
//golang
if a == "test64bytes" {
output = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"
}
// encrypt ajax response
iv := decodeBase64("AAAAAAAAAAAAAAAAAAAAAA==")
ciphertext := []byte(output)
ckey := decodeBase64(string(PLAINkey[0:32]))
c, err := aes.NewCipher(ckey)
cfbdec := cipher.NewCBCDecrypter(c, iv)
plaintext := make([]byte, len(ciphertext))
cfbdec.CryptBlocks(plaintext, ciphertext)
crypt := string(encodeBase64(plaintext))
fmt.Fprintf(res, "%v", crypt)
fmt.Println(encodeBase64(ckey))
fmt.Println(encodeBase64(iv))
fmt.Println(crypt)
// javascript
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var enc = {};
enc["key"] = CryptoJS.enc.Base64.parse(keyseed.substring(0,32));
enc["iv"] = CryptoJS.enc.Base64.parse("AAAAAAAAAAAAAAAAAAAAAA==");
enc["ciphertext"] = CryptoJS.enc.Base64.parse(xmlhttp.responseText);
enc["salt"] = "";
console.log("RESPONSE:", xmlhttp.responseText, atob(xmlhttp.responseText));
// check i'm using same data
console.log(CryptoJS.enc.Base64.stringify(enc["key"]));
console.log(CryptoJS.enc.Base64.stringify(enc["iv"]));
console.log(CryptoJS.enc.Base64.stringify(enc["ciphertext"]));
var options = { keySize: 256 / 8, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: enc["iv"] };
de = CryptoJS.AES.decrypt(enc, enc["key"], options);
document.getElementById(target).innerHTML = de.toString();
console.log(de.toString(CryptoJS.enc.Utf8));
console.log("DECRYPTION FINISHED");
}
After methodically trying all possible AES configurations I can now decrypt my text..
...using a blank iv ("AAAAAAAAAAAAAAAAAAAAAA==") for this example. If you use a different one it will become the first block of plaintext when encrypting...
Go > CryptoJS
// Go
plaintext := []byte("THIS NEEDS TO BE MULTIPLE OF BLOCK LENGTH (16) I THINK")
// encrypt ajax response
iv := decodeBase64("AAAAAAAAAAAAAAAAAAAAAA==")
ckey := decodeBase64(string(PLAINkey[0:32]))
c, err := aes.NewCipher(ckey)
cfbdec := cipher.NewCBCEncrypter(c, iv)
ciphertext := make([]byte, len(plaintext))
cfbdec.CryptBlocks(ciphertext, plaintext)
crypt := string(encodeBase64(ciphertext))
fmt.Fprintf(res, "%v", crypt)
// JavaScript Ajax
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var symkey = keyseed.substring(0,32);
var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(xmlhttp.responseText) });
var options = { mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.NoPadding, iv: CryptoJS.enc.Base64.parse("AAAAAAAAAAAAAAAAAAAAAA==") };
de = CryptoJS.AES.decrypt(cipherParams, CryptoJS.enc.Base64.parse(symkey), options);
document.getElementById(target).innerHTML = de.toString(CryptoJS.enc.Utf8);
console.log("DECRYPTION FINISHED");
}
Related
I have a HMAC validation code in PHP which is like
$calculatedHmac = base64_encode(hash_hmac('sha256', json_encode($input), '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', true));
if($calculatedHmac === $this->app['request']->header('X-Shopify-Hmac-Sha256'))
{
echo "Correct HMAC";
}
Now, I am trying to do the same validation in GoLang. The corresponding code:
hash := hmac.New(sha256.New, []byte('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'))
inputData, _ := json.Marshal(input)
fmt.Println(string(inputData))
hash.Write(inputData)
base64EncodedStr := base64.StdEncoding.EncodeToString(hash.Sum(nil))
hexEncodedStr := hex.EncodeToString(hash.Sum(nil))
if requestHmac == base64EncodedStr {
logger.GetEntryWithContext(ctx).Infow("JsonMarshal.Base64 worked", nil)
} else if hexEncodedStr == requestHmac {
logger.GetEntryWithContext(ctx).Infow("JsonMarshal.Hex Encoding worked", nil)
}
Anything that I am doing wrong???
Input data:
Actual HMAC: EUF2feuOuaQzh0bhSE8eCaI23BM0Qh+yBtmxNWyt8JQ=
JSON Input:
{"address1":"Ghar ka Address","address2":null,"auto_configure_tax_inclusivity":null,"checkout_api_supported":false,"city":"Bangalore ","cookie_consent_level":"implicit","country":"IN","country_code":"IN","country_name":"India","county_taxes":true,"created_at":"2021-03-06T11:54:22+05:30","currency":"INR","customer_email":"amit.vickey#razorpay.com","domain":"rzp-sample-store.myshopify.com","eligible_for_card_reader_giveaway":false,"eligible_for_payments":false,"email":"amit.vickey#razorpay.com","enabled_presentment_currencies":["INR"],"finances":true,"force_ssl":true,"google_apps_domain":null,"google_apps_login_enabled":null,"has_discounts":false,"has_gift_cards":false,"has_storefront":true,"iana_timezone":"Asia/Calcutta","id":55091921055,"latitude":12.9142148,"longitude":77.61210129999999,"money_format":"Rs. {{amount}}","money_in_emails_format":"Rs. {{amount}}","money_with_currency_format":"Rs. {{amount}}","money_with_currency_in_emails_format":"Rs. {{amount}}","multi_location_enabled":true,"myshopify_domain":"rzp-sample-store.myshopify.com","name":"RZP Sample Store","password_enabled":true,"phone":"","plan_display_name":"Developer Preview","plan_name":"partner_test","pre_launch_enabled":false,"primary_locale":"en","primary_location_id":61106618527,"province":"Karnataka","province_code":"KA","requires_extra_payments_agreement":false,"setup_required":false,"shop_owner":"Amit Vickey","source":null,"tax_shipping":null,"taxes_included":false,"timezone":"(GMT+05:30) Asia/Calcutta","updated_at":"2021-03-06T12:06:18+05:30","visitor_tracking_consent_preference":"allow_all","weight_unit":"kg","zip":"560076"}
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.")
}
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).
I have integrated Zap with my go application, we have logs getting printed in two log files and i am also using Lumberjack for log rotation. But i am trying to display the logs in console as well, but no luck for this case.
Following is my code in logger.go
var (
Logger *zap.Logger
N2n *zap.Logger
)
type WriteSyncer struct {
io.Writer
}
func (ws WriteSyncer) Sync() error {
return nil
}
func InitLogging(mode string) {
var cfg zap.Config
var logName = "abc.log"
var slogName = "n2n.log"
if mode == "production" {
cfg = zap.NewProductionConfig()
cfg.DisableCaller = true
} else {
cfg = zap.NewDevelopmentConfig()
cfg.EncoderConfig.LevelKey = "level"
cfg.EncoderConfig.NameKey = "name"
cfg.EncoderConfig.MessageKey = "msg"
cfg.EncoderConfig.CallerKey = "caller"
cfg.EncoderConfig.StacktraceKey = "stacktrace"
}
cfg.Encoding = "json"
cfg.EncoderConfig.TimeKey = "timestamp"
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
cfg.OutputPaths = []string{logName}
sw := getWriteSyncer(logName)
swSugar := getWriteSyncer(slogName)
l, err := cfg.Build(SetOutput(sw, cfg))
if err != nil {
panic(err)
}
defer l.Sync()
ls, err := cfg.Build(SetOutput(swSugar, cfg))
if err != nil {
panic(err)
}
defer ls.Sync()
Logger = l
N2n = ls
}
// SetOutput replaces existing Core with new, that writes to passed WriteSyncer.
func SetOutput(ws zapcore.WriteSyncer, conf zap.Config) zap.Option {
var enc zapcore.Encoder
switch conf.Encoding {
case "json":
enc = zapcore.NewJSONEncoder(conf.EncoderConfig)
case "console":
enc = zapcore.NewConsoleEncoder(conf.EncoderConfig)
default:
panic("unknown encoding")
}
return zap.WrapCore(func(core zapcore.Core) zapcore.Core {
return zapcore.NewCore(enc, ws, conf.Level)
})
}
func getWriteSyncer(logName string) zapcore.WriteSyncer {
var ioWriter = &lumberjack.Logger{
Filename: logName,
MaxSize: 10, // MB
MaxBackups: 3, // number of backups
MaxAge: 28, //days
LocalTime: true,
Compress: false, // disabled by default
}
var sw = WriteSyncer{
ioWriter,
}
return sw
}
I have tried appending the output paths but it is not working.
Since this is one of the first things that appears after looking for this on Google, here's a simple example of how to make logs show on the Console and a log file, which can be any io.Writer as the one used by lumberjack:
func logInit(d bool, f *os.File) *zap.SugaredLogger {
pe := zap.NewProductionEncoderConfig()
fileEncoder := zapcore.NewJSONEncoder(pe)
pe.EncodeTime = zapcore.ISO8601TimeEncoder # The encoder can be customized for each output
consoleEncoder := zapcore.NewConsoleEncoder(pe)
level := zap.InfoLevel
if d {
level = zap.DebugLevel
}
core := zapcore.NewTee(
zapcore.NewCore(fileEncoder, zapcore.AddSync(f), level),
zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level),
)
l := zap.New(core) # Creating the logger
return l.Sugar()
}
I used the default ProductionEncoderConfig but it could be a custom one like the one on OP's code.
Figured out that zapcore has zapcore.NewMultiWriteSyncer which can write the logs in file and also on console using zapcore.addSync(os.stdout).
For example:
swSugar := zapcore.NewMultiWriteSyncer(
zapcore.AddSync(os.Stdout),
getWriteSyncer(logfileName),
)
You can also use zap.CombineWriteSyncers:
CombineWriteSyncers is a utility that combines multiple WriteSyncers into a single, locked WriteSyncer. If no inputs are supplied, it returns a no-op WriteSyncer.
It's provided purely as a convenience; the result is no different from using zapcore.NewMultiWriteSyncer and zapcore.Lock individually.
syncer := zap.CombineWriteSyncers(os.Stdout, getWriteSyncer(logfileName))
core := zapcore.NewCore(enc, syncer, zap.NewAtomicLevelAt(zap.InfoLevel))
zap.New(core)
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