What is right way doing aes gcm decription with sjcl.js?

1.2k views Asked by At

I am trying to decrypt cipher content with sjcl.js crypto library in aes algorithm(gcm mode). This is my code:

//encrypted data and key
let key = "8mUzwnewfaBFKiGW/rO5Xw=="
let cipherText ="Oz9IH7sElYzEyLCQoHJZJgH6z4J3INJtJyrpQzFQg3dRbEFIla4r4ox0ktA/Sh077fvCnnaMrCKu9PiYOQiRN7bS7EAXKgdiMN/zL98j4HyeVB9nRrH2PVXGKL+TcjM3F+kScl0DyCHJxHiXb+rKhXlYc/3T2ulBV8xIwk+S0IdV5TwjIfLIY7lxWcvZt9Mi2JEt9C54RFU3nFQIexSPIpoLtwnonbguSlx/KsNYgpObhlhRsC9W/Ix2m4n6eDxfQWCuhQp5614OiizBzgKBD1dKkjpGvUajZqhVwW4/AY6BwqucflasjAq9IPPcu5/+s4ittsXiDlKV66xHzTlKOcOBsVUEofzOQpN/zutktG9KG1zBsdhP6btM/c/5pehHJMX4gnZJfXVx/pVxzFG/eQysvGJ2F8dxKggfdJN7wd/QYJDaaJySW5cduL7bWoo7yXssAWobXnCedji+SwCprDmtGQEpyeOq03/7hyQbMe6m4iFbw2bsJGsAXHtnVVxFBoIp8wEGxKY5ji+p7jUe20vPomJ5VvAqEegV+nRq99O66MbbK9/s1+/6gILl7P80Sq5jNUA="

//tag, adata, iv lengths in bits
const GCM_TAG_LENGTH = 16 * 8
const GCM_AAD_LENGTH = 16 * 8
const GCM_NONCE_LENGTH = 12 * 8

let bkey = sjcl.codec.base64.toBits(key)
let bdata = sjcl.codec.base64.toBits(cipherText)
let cipher = new sjcl.cipher.aes(bkey)

let aad = sjcl.bitArray.bitSlice(bdata, 0, GCM_AAD_LENGTH)
let iv = sjcl.bitArray.bitSlice(aad, GCM_NONCE_LENGTH * -1)
let tag = sjcl.bitArray.bitSlice(bdata, GCM_TAG_LENGTH * -1)
let data = sjcl.bitArray.bitSlice(bdata, GCM_AAD_LENGTH, GCM_TAG_LENGTH * -1)
let decryptedContent = ''

let decbits = sjcl.mode.gcm.decrypt(cipher,data,iv,aad,tag)
decryptedContent = sjcl.codec.utf8String.fromBits(decbits)
console.log('decryptedContent', decryptedContent) // empty

key and cipherText are already encrypted in python (aes-gcm, 128bitkey). Does anybody know how to decrypt it? Are there any alternatives to sjcl.js with documentation? Thanks!

NOTE: I have already decrypted it with NodeJS Crypto lib but Crypto lib is not compatable with browser. Browserifying it makes a heavy script so i am looking for broswer compatible, lightweight javascript lib.This is my code with NodeJs:

function decrypt(key, content) {
  return new Promise((resolve, reject) => {
    let keyBuffer = new Buffer(key, 'base64')

    const AES_KEY_SIZE = keyBuffer.length * 8
    const GCM_TAG_LENGTH = 16
    const GCM_AAD_LENGTH = 16
    const GCM_NONCE_LENGTH = 12

    let contentBuffer = new Buffer(content, 'base64')
    let aad = contentBuffer.slice(0, GCM_AAD_LENGTH)
    let iv = aad.slice(GCM_NONCE_LENGTH * -1)
    let tag = contentBuffer.slice(GCM_TAG_LENGTH * -1)
    let cipherText = contentBuffer.slice(GCM_AAD_LENGTH, GCM_TAG_LENGTH * -1)
    let decryptedContent = ''

    try {
        let decipher = crypto.createDecipheriv(`aes-${AES_KEY_SIZE}-gcm`, keyBuffer, iv)
        decipher.setAAD(aad)
        decipher.setAuthTag(tag)
        decryptedContent = decipher.update(cipherText, 'binary', 'utf8') + decipher.final('utf8')
        return resolve(decryptedContent)
    } catch (e) {
        reject(e.message || e)
    }
})}
1

There are 1 answers

0
Ismayil Niftaliyev On

At the end I found the reason and Maarten you were rigth. sjcl.js tries to extract tag from decrypted content but I already extracted tag so that was the issue. Replaced the line:

let data = sjcl.bitArray.bitSlice(bdata, GCM_AAD_LENGTH, GCM_TAG_LENGTH * -1)

with this line:

let data = sjcl.bitArray.bitSlice(bdata, GCM_AAD_LENGTH)

And solved the issue.This is final(working) version:

let key = "[base64 key]"
let cipherText ="[base64 encrypted data]"
const GCM_TAG_LENGTH = 16 *8
const GCM_AAD_LENGTH = 16 *8
const GCM_NONCE_LENGTH = 12 *8

let bkey = sjcl.codec.base64.toBits(key)
let bdata = sjcl.codec.base64.toBits(cipherText)
let cipher = new sjcl.cipher.aes(bkey)


let aad =sjcl.bitArray.bitSlice(bdata, 0, GCM_AAD_LENGTH)
let iv = sjcl.bitArray.bitSlice(aad, GCM_NONCE_LENGTH * -1)
let tag =sjcl.bitArray.bitSlice(bdata, GCM_TAG_LENGTH * -1)
let data = sjcl.bitArray.bitSlice(bdata, GCM_AAD_LENGTH)
let decryptedContent = ''

let decbits = sjcl.mode.gcm.decrypt(cipher, data, iv, aad, GCM_TAG_LENGTH)
decryptedContent = sjcl.codec.utf8String.fromBits(decbits)
console.log('decryptedContent', decryptedContent)