Json generated from FE (javascript) validated by BE (golang).

This commit is contained in:
Tan Xiang 2018-09-06 09:38:47 +00:00
parent 28ce1dd6b8
commit 74daccebf1
8 changed files with 133 additions and 93 deletions

View File

@ -33,7 +33,7 @@ func (obj *SecureJson) encrypt(plainText []byte, iv []byte, key []byte) ([]byte,
func (obj *SecureJson) genHash(userBytes []byte, encryptedBytes []byte, timeBytes []byte, pubkeyBytes []byte) (fullHash []byte) {
userHash, _ := obj.hash(userBytes)
dataHash, _ := obj.hash(encryptedBytes)
timeHash, _ := obj.hash(timeBytes[:4])
timeHash, _ := obj.hash(timeBytes)
pubkeyHash, _ := obj.hash(pubkeyBytes[:65])
full := make([]byte, 32*4)
@ -159,10 +159,18 @@ func (obj *SecureJson) getTimestamp() ([]byte, error) {
return timeNowBytes, err
}
func (obj *SecureJson) hash(data []byte) ([]byte, error) {
sum := make([]byte, 32)
func (obj *SecureJson) shake256(data []byte, length int) ([]byte, error) {
sum := make([]byte, length)
hashObj := sha3.NewShake256()
hashObj.Write(data)
hashObj.Read(sum)
return sum, nil
}
func (obj *SecureJson) hash(data []byte) ([]byte, error) {
return obj.shake256(data, 32)
}
func (obj *SecureJson) genIv(userName string) ([]byte, error) {
return obj.shake256([]byte(userName), 16)
}

1
js/aes/index.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
js/base64/base64js.min.js vendored Normal file
View File

@ -0,0 +1 @@
(function(r){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=r()}else if(typeof define==="function"&&define.amd){define([],r)}else{var e;if(typeof window!=="undefined"){e=window}else if(typeof global!=="undefined"){e=global}else if(typeof self!=="undefined"){e=self}else{e=this}e.base64js=r()}})(function(){var r,e,n;return function(){function r(e,n,t){function o(f,i){if(!n[f]){if(!e[f]){var u="function"==typeof require&&require;if(!i&&u)return u(f,!0);if(a)return a(f,!0);var v=new Error("Cannot find module '"+f+"'");throw v.code="MODULE_NOT_FOUND",v}var d=n[f]={exports:{}};e[f][0].call(d.exports,function(r){var n=e[f][1][r];return o(n||r)},d,d.exports,r,e,n,t)}return n[f].exports}for(var a="function"==typeof require&&require,f=0;f<t.length;f++)o(t[f]);return o}return r}()({"/":[function(r,e,n){"use strict";n.byteLength=d;n.toByteArray=h;n.fromByteArray=p;var t=[];var o=[];var a=typeof Uint8Array!=="undefined"?Uint8Array:Array;var f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var i=0,u=f.length;i<u;++i){t[i]=f[i];o[f.charCodeAt(i)]=i}o["-".charCodeAt(0)]=62;o["_".charCodeAt(0)]=63;function v(r){var e=r.length;if(e%4>0){throw new Error("Invalid string. Length must be a multiple of 4")}var n=r.indexOf("=");if(n===-1)n=e;var t=n===e?0:4-n%4;return[n,t]}function d(r){var e=v(r);var n=e[0];var t=e[1];return(n+t)*3/4-t}function c(r,e,n){return(e+n)*3/4-n}function h(r){var e;var n=v(r);var t=n[0];var f=n[1];var i=new a(c(r,t,f));var u=0;var d=f>0?t-4:t;for(var h=0;h<d;h+=4){e=o[r.charCodeAt(h)]<<18|o[r.charCodeAt(h+1)]<<12|o[r.charCodeAt(h+2)]<<6|o[r.charCodeAt(h+3)];i[u++]=e>>16&255;i[u++]=e>>8&255;i[u++]=e&255}if(f===2){e=o[r.charCodeAt(h)]<<2|o[r.charCodeAt(h+1)]>>4;i[u++]=e&255}if(f===1){e=o[r.charCodeAt(h)]<<10|o[r.charCodeAt(h+1)]<<4|o[r.charCodeAt(h+2)]>>2;i[u++]=e>>8&255;i[u++]=e&255}return i}function s(r){return t[r>>18&63]+t[r>>12&63]+t[r>>6&63]+t[r&63]}function l(r,e,n){var t;var o=[];for(var a=e;a<n;a+=3){t=(r[a]<<16&16711680)+(r[a+1]<<8&65280)+(r[a+2]&255);o.push(s(t))}return o.join("")}function p(r){var e;var n=r.length;var o=n%3;var a=[];var f=16383;for(var i=0,u=n-o;i<u;i+=f){a.push(l(r,i,i+f>u?u:i+f))}if(o===1){e=r[n-1];a.push(t[e>>2]+t[e<<4&63]+"==")}else if(o===2){e=(r[n-2]<<8)+r[n-1];a.push(t[e>>10]+t[e>>4&63]+t[e<<2&63]+"=")}return a.join("")}},{}]},{},[])("/")});

File diff suppressed because one or more lines are too long

View File

@ -1,51 +1,32 @@
var EC = require('./elliptic/elliptic.min').ec;
var SHA3 = require('./sha3/sha3.min');
var CRYPTO = require('./crypto/crypto-js.min');
var AES = require('./aes/index.min')
var BASE64 = require('./base64/base64js.min')
// Create and initialize EC context
// (better do it once and reuse it)
var ec = new EC('secp256k1');
var jsonStr = GenerateJson("MyUser", "1234", "MyData");
console.log(jsonStr);
var out = CRYPTO.AES.encrypt("aaa", "bbb", {mode: CRYPTO.mode.CTR, iv: "aaaa"});
//console.log(out)
function bytesToBase64(bytes) {
return BASE64.fromByteArray(bytes);
}
var ts = Math.round((new Date()).getTime() / 1000);
console.log(ts);
function base64ToBytes(str) {
return BASE64.toByteArray(str);
}
// Generate keys
/*
var key = ec.genKeyPair();
prihex = key.getPrivate('hex')
pubhex = key.getPublic(false, 'hex')
*/
//console.log(SHA3.shake256("1234", 256))
//console.log(window.performance.now())
//var prihex = "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721";
var prihex = SHA3.shake256('1234', 256);
function base64ToHex(str) {
return bytesToHex(base64ToBytes(str));
}
var keys = ec.keyFromPrivate(prihex, 'hex');
var pubhex = keys.getPublic(false, 'hex');
//console.log(prihex.length/2)
//console.log(prihex)
//console.log(pubhex.length/2);
//console.log(pubhex);
function hexToBase64(hex) {
return bytesToBase64(hexToBytes(hex));
}
pubkey = ec.keyFromPublic(pubhex, 'hex');
prikey = ec.keyFromPrivate(prihex, 'hex');
var msg = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var sig = ec.sign(msg, prikey);
//console.log(ec.verify(msg, sig, pubkey));
// Sign the message's hash (input must be an array, or a hex-string)
var msgHash = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var signature = prikey.sign(msgHash);
// Export DER encoded signature in Array
var derSign = signature.toDER();
// Verify signature
//console.log(pubkey.verify(msgHash, derSign));
function encrypt(dataBytes, ivBytes, keyBytes) {
var aesCtr = new AES.ModeOfOperation.ctr(keyBytes, ivBytes);
var encryptedBytes = aesCtr.encrypt(dataBytes);
return encryptedBytes;
}
function GenerateJson(user, passwd, data) {
var ec = new EC('secp256k1');
@ -55,7 +36,25 @@ function GenerateJson(user, passwd, data) {
var pubkeyHex = prikey.getPublic(false, 'hex');
var pubkey = ec.keyFromPublic(pubkeyHex, 'hex');
var iv = SHA3.shake256(user, 256);
var iv = SHA3.shake256(user, 128);
var encryptedDataBytes = encrypt(stringToBytes(data), hexToBytes(iv), hexToBytes(prikeyHex));
var encryptedDataHex = bytesToHex(encryptedDataBytes);
var timestampHex = bytesToHex(intToBytes(getTimestamp()));
var userHex = bytesToHex(stringToBytes(user));
var fullHash = genHash(userHex, encryptedDataHex, timestampHex, pubkeyHex);
var sigHex = bytesToHex(prikey.sign(fullHash).toDER());
var obj = {
UserName : user,
Signature : hexToBase64(sigHex),
EncryptedData : hexToBase64(encryptedDataHex),
Timestamp : hexToBase64(timestampHex),
PublicKey : hexToBase64(pubkeyHex)
};
jsonStr = JSON.stringify(obj);
return jsonStr;
}
function getPriKey(prikeyHex) {
@ -73,18 +72,35 @@ function getTimestamp() {
return Math.round((new Date()).getTime() / 1000);
}
function genHash(user, data, time, pubkey) {
var userHash = SHA3.shake256.array(hexToBytes(user), 256);
var dataHash = SHA3.shake256.array(hexToBytes(data), 256);
var timeHash = SHA3.shake256.array(hexToBytes(time), 256);
var pubkeyHash = SHA3.shake256.array(hexToBytes(pubkey), 256);
function intToBytes(numb) {
var bytesLen = 4;
var bytes = new Array(bytesLen-1);
for(var i=bytesLen; i>0; i--) {
bytes[i-1] = numb & 0xff;
numb = numb>>8;
}
return bytes;
}
function genHash(userHex, dataHex, timeHex, pubkeyHex) {
var userHash = SHA3.shake256.array(hexToBytes(userHex), 256);
var dataHash = SHA3.shake256.array(hexToBytes(dataHex), 256);
var timeHash = SHA3.shake256.array(hexToBytes(timeHex), 256);
var pubkeyHash = SHA3.shake256.array(hexToBytes(pubkeyHex), 256);
var full = Array();
//full.concat( hexToBytes(userHash), hexToBytes(dataHash), hexToBytes(timeHash), hexToBytes(pubkeyHash) );
full.concat( userHash, pubkeyHash, timeHash, dataHash );
full = full.concat( userHash, pubkeyHash, timeHash, dataHash );
var fullHash = SHA3.shake256.array(full, 256);
return fullHash
}
function bytesToString(bytes) {
return AES.utils.hex.fromBytes(bytes);
}
function stringToBytes(str) {
return AES.utils.utf8.toBytes(str);
}
function hexToBytes(hex) {
var len = hex.length;
if(len%2!=0) {

View File

@ -24,7 +24,7 @@ type Json struct {
}
func (obj *SecureJson) Encrypt(data string, userName string, key []byte) (string, error) {
iv, _ := obj.hash([]byte(userName))
iv, _ := obj.genIv(userName)
cipherBytes, err := obj.encrypt([]byte(data), iv, key)
return obj.bytesToString(cipherBytes), err
}
@ -67,17 +67,18 @@ func (obj *SecureJson) VerifyJson(jsonBytes []byte) (ok bool, err error) {
}
if !obj.checkTimestampBeforeNow(jsonMap.Timestamp) {
err = errors.New("Timestamp check fail")
return false, err
}
userData := []byte(jsonMap.UserName)
encryptedData := obj.stringToBytes(jsonMap.EncryptedData)
timeData := obj.stringToBytes(jsonMap.Timestamp)
pubkeyData := obj.stringToBytes(jsonMap.PublicKey)
sigData := obj.stringToBytes(jsonMap.Signature)
fullHash := obj.genHash(userData, encryptedData, timeData, pubkeyData)
userBytes := []byte(jsonMap.UserName)
encryptedBytes := obj.stringToBytes(jsonMap.EncryptedData)
timeBytes := obj.stringToBytes(jsonMap.Timestamp)
pubkeyBytes := obj.stringToBytes(jsonMap.PublicKey)
sigBytes := obj.stringToBytes(jsonMap.Signature)
fullHash := obj.genHash(userBytes, encryptedBytes, timeBytes, pubkeyBytes)
ok = obj.verify(fullHash, pubkeyData, sigData)
ok = obj.verify(fullHash, pubkeyBytes, sigBytes)
if ok {
return
} else {

View File

@ -24,17 +24,39 @@ func (obj *StubStorage) Get(key string) ([]byte, error) {
return obj.jsonBytes, nil
}
func testJson(jsonBytes []byte, logprifix string, obj *SecureJson) {
ok, err := obj.VerifyJson(jsonBytes)
if err != nil || !ok {
fmt.Println(err)
fmt.Println(logprifix, "Verify the Json Fail")
}
var data Json
err = json.Unmarshal(jsonBytes, &data)
if err != nil {
fmt.Println(logprifix, "Json Unmarshal Fail")
}
passwd, _ := obj.hash([]byte("1234"))
plain, err := obj.Decrypt(data.EncryptedData, data.UserName, passwd)
if err != nil {
fmt.Println(logprifix, "Decrypt Fail")
}
if string(plain) != "MyData" {
fmt.Println(logprifix, "Decrypted data Fail")
}
}
func ExampleNew() {
storage := new(StubStorage)
obj := New(storage)
jsonBytes := []byte(`{"UserName":"MyUser","Signature":"MEUCIDJmafX+XGJV+Ws2jz0lF2YdJLcrEXAw1ZBPB0/+KjJyAiEA1CR3f/pbngSl0P0mqb7McKSbveSsQ1ir5L4ulpKamuw=","EncryptedData":"F4Zw1vYy","Timestamp":"W5D07g==","PublicKey":"BCNhwc+1nmUYLSDJnacQaKQB1YyT26gdwHCZZd1iwsB14rfGvwv9fuAHjyln9Alap2Voxp/rrdiU2QvE8HuMt5s="}`)
testJson(jsonBytes, "Hardcoded", obj)
jsonBytes, err := obj.GenerateJson("MyUser", "1234", "MyData")
if err != nil {
panic(err)
}
ok, err := obj.VerifyJson(jsonBytes)
if err != nil || !ok {
fmt.Println("Verify the Generated Json Fail")
}
testJson(jsonBytes, "Generated", obj)
_, err = obj.GetJson(jsonBytes)
if err == nil {
fmt.Println("Expecting error when no value stored")
@ -45,27 +67,10 @@ func ExampleNew() {
}
_, err = obj.GetJson(jsonBytes)
if err != nil {
fmt.Println(err)
fmt.Println("Get Json Fail")
}
ok, err = obj.VerifyJson(jsonBytes)
if err != nil {
fmt.Println("Verify Json Fail")
}
var data Json
err = json.Unmarshal(jsonBytes, &data)
if err != nil {
fmt.Println("Json Unmarshal Fail")
}
passwd, _ := obj.hash([]byte("1234"))
plain, err := obj.Decrypt(data.EncryptedData, data.UserName, passwd)
if err != nil {
fmt.Println("Decrypt Fail")
}
if string(plain) != "MyData" {
fmt.Println("Decrypted data Fail")
}
fmt.Println(ok)
testJson(jsonBytes, "Get", obj)
fmt.Println(true)
//output:
//true
}

11
utils.go Normal file
View File

@ -0,0 +1,11 @@
package securejson
import (
"fmt"
"encoding/hex"
)
func dumpBytes(prifix string, bytes []byte) {
hexString := hex.EncodeToString(bytes)
fmt.Println(prifix, hexString)
}