A solution to store client-side encrypted JSON in a backend that has no knowledge of the unencrypted contents. JavaScript frontend -> Go backend
Go to file
kayos@tcp.direct caffb56165
Add entropic test case
2022-09-19 15:41:56 -07:00
.github/workflows CI: Implement gosec 2022-07-09 11:13:09 -07:00
js Adjust naming schemes to conform to standard, improve testing 2022-07-09 10:49:04 -07:00
.gitignore Fix implementation, tests, and implement go modules 2022-07-09 10:16:08 -07:00
LICENSE Initial commit 2018-08-31 09:24:11 +08:00
README.md Adjust naming schemes to conform to standard, improve testing 2022-07-09 10:49:04 -07:00
compute.go Add entropic test case 2022-09-19 15:41:56 -07:00
go.mod Update go module path 2022-07-09 15:10:04 -07:00
go.sum Fix implementation, tests, and implement go modules 2022-07-09 10:16:08 -07:00
securejson.go Add entropic test case 2022-09-19 15:41:56 -07:00
securejson_test.go Add entropic test case 2022-09-19 15:41:56 -07:00
utils.go Json generated from FE (javascript) validated by BE (golang). 2018-09-06 09:38:47 +00:00

securejson

A solution to secure the json content between BE and FE. The secure content only handled by FE, BE verify user's signature and store the encrypted secure content, but never know what is it.

Why to use this project:

  • Server never know the content of secure data, it's handled by client only.
  • Server never konw the user's password, it's handled by client only.

How does this project implemented:

  • FE implemented by js, BE implemented by go.
  • It's using AES-CTR to encrypt the secure data
  • It's using SHA3-256 (SHAKE) to hash the json content.
  • It's using ECDSA to signing the hash
  • It's using base64 to encode the data.

How to use in browser (javascript)

In HTML

In your html file, require.js is needed to be included. Below is an example to include the require.js from a CDN, and indicate the main file of javascript is "js/main.js".

<script data-main="js/main.js" src="https://cdn.bootcss.com/require.js/2.3.5/require.js"></script>

In js

In your main file of javascript, the path of dependency libs should be defined in order to let require.js find the dependency. Then, a object of securejson should be created, using require() function provided by require.js. Then, call the function "GenerateJSON" to generate a secured json string. Below is an example of main.js

var secureJSON;

require.config({
	baseUrl: 'js',
	paths: {
		securejson: '3rd/securejson',
		elliptic: "3rd/elliptic/elliptic.min",
		sha3: "3rd/sha3/sha3.min",
		aes: "3rd/aes/index.min",
		base64: "3rd/base64/base64js.min"
	},
});
require(['securejson'], function(sj){
	secureJSON = sj;
});
var jsonString = secureJSON.GenerateJSON("My User Name", "My Password", "My sucure data");
console.log(jsonString);

And, for this example, the file structure shoud be like this:

js/
js/3rd/
js/3rd/aes/
js/3rd/aes/index.min.js
js/3rd/base64/
js/3rd/base64/base64js.min.js
js/3rd/elliptic/
js/3rd/elliptic/elliptic.min.js
js/3rd/sha3/
js/3rd/sha3/sha3.min.js
js/securejson.js
js/main.js

API for Front-end

GenerateJSON(userName, passwd, data)
  • userName: The user name to identify the owner of the data.
  • passwd: User password. It's used to generate the private key used for signing the json, and also used to encrypt the plain data.
  • data: The plain data to be secured.

How to use in server (golang)

Implement Storage interface

This package does not implement the storage. The storage can be memory, file, database depend on your use cases. The storage interface is very simple, only 2 functions should be implemented:

  • Get() to get the value identified by key.
  • Put() to set the value identified by key. Below given a stub implementation of Storage interface
type StubStorage struct {
	jsonBytes []byte
}

func (obj *StubStorage) Put(key string, value []byte) error {
	obj.jsonBytes = value
	//fmt.Println("Put", string(obj.jsonBytes))
	return nil
}

func (obj *StubStorage) Get(key string) ([]byte, error) {
	if len(obj.jsonBytes) == 0 {
		return []byte{}, errors.New("Empty")
	}
	//fmt.Println("Get", string(obj.jsonBytes))
	return obj.jsonBytes, nil
}

Verify then store a json bytes

jsonBytes := []byte(`{"UserName":"MyUser","Signature":"MEUCIDJmafX+XGJV+Ws2jz0lF2YdJLcrEXAw1ZBPB0/+KjJyAiEA1CR3f/pbngSl0P0mqb7McKSbveSsQ1ir5L4ulpKamuw=","EncryptedData":"F4Zw1vYy","Timestamp":"W5D07g==","PublicKey":"BCNhwc+1nmUYLSDJnacQaKQB1YyT26gdwHCZZd1iwsB14rfGvwv9fuAHjyln9Alap2Voxp/rrdiU2QvE8HuMt5s="}`)
storage := new(StubStorage)
obj := securejson.New(storage)
ok, err := obj.VerifyJSON(jsonBytes)
if ok {
	obj.PutJSON(jsonBytes)
}

Get json bytes from storage

outJSONBytes, err := obj.GetJSON(jsonBytes)
  • GetJSON need to input a jsonBytes generated by GenerateJSON() function of both FE and BE. It's used to verify the data requester is a valid owner of the specific secure data.