Digital Signature
A digital signature is a mathematical technique used to validate the authenticity and integrity of a message, software or digital document. It is intended to solve the problem of tampering and impersonation in digital communications. The below diagram depicts the process of digital signature creation and verification. All API endpoints expect the request payload to be signed by the calling program with private key issued using ECDSA algorithm.
Sample Code
- Java
- Go
- Javascript
public static String createSignature(String message) throws Exception {
PrivateKey = KeyFactory.getInstance("EC").generatePrivate(getPemPrivateKey());
java.security.Signature signature = java.security.Signature.getInstance("SHA256withECDSA");
signature.initSign(privateKey);
signature.update(message.getBytes("UTF-8"));
byte[] bytes = signature.sign();
return java.util.Base64.getEncoder().encodeToString(bytes);
}
public static PKCS8EncodedKeySpec getPemPrivateKey() throws Exception {
FileInputStream fis = new FileInputStream("/etc/ssl/certs/private.pem");
String temp = IOUtils.toString(fis, "UTF-8");
String privKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----", "");
privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", "");
Base64 b64 = new Base64();
byte[] decoded = b64.decode(privKeyPEM);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
return spec;
}
func Sign(payload []byte) (string, error) {
pk, derr := DecodePrivateKeyFromFile()
if derr != nil {
log.Fatalf("Error while decode provate key: %v", derr)
return "", derr
}
hash := sha256.Sum256(payload)
r, s, err := ecdsa.Sign(rand.Reader, pk, hash[:])
if err != nil {
log.Println(err)
return "", err
}
b, ee := asn1.Marshal(ECDSASignature{r, s})
if ee != nil {
log.Println(ee)
return "", ee
}
signature := base64.StdEncoding.EncodeToString(b)
return signature, nil
}
func DecodePrivateKeyFromFile() (*ecdsa.PrivateKey, error) {
bts, err := ioutil.ReadFile(privateKeyPath)
if err != nil {
log.Println("Error reading file: ", err)
}
block, _ := pem.Decode(bts)
if block == nil {
return nil, errors.New("Failed to decode PEM private key")
}
x509Encoded := block.Bytes
privateKey, err := x509.ParsePKCS8PrivateKey(x509Encoded)
if err != nil {
return nil, errors.New("Failed to parse ECDSA private key")
}
switch privateKey := privateKey.(type) {
case *ecdsa.PrivateKey:
return privateKey, nil
}
return nil, errors.New("Unsupported public key type")
}
type ECDSASignature struct {
R, S *big.Int
}
<script src="http://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js"></script>
<script>
function signPayload(payload){
var privateKey = getPrivateKey()
var signature_algo = "SHA256withECDSA";
var payloadStr = JSON.stringify(payload)
var sig = new KJUR.crypto.Signature({
"alg": signature_algo
});
sig.init(privateKey);
sig.updateString(payloadStr);
var sigValueHex = sig.sign();
var sigBase64 = hextob64(sigValueHex);
return sigBase64
}
function getPrivateKey(){
const fs = require('fs')
let pk = ""
fs.readFile('pk.txt', 'utf-8', (err, data) => {
if (err) throw err;
pk = data
})
let pks = pk.split(/\\n/)
var privateKey = ""
for (let i = 0; i < pks.length; i++) {
privateKey += pks[i] + "\n"
}
return privateKey
}
</script>