0.2.10 • Published 3 years ago

cosmian_jslib v0.2.10

Weekly downloads
-
License
MIT
Repository
-
Last release
3 years ago

Cosmian JS Lib

This library provides cryptographic primitives to be used in the browser.

Most of the cryptographic code is developed in Rust and compiled to Web Assembly. The WASM files are delivered as part of this library.

Hybrid Cryptography

This library provides the ability to encrypt and decrypt file, in the browser, using hybrid cryptography.

Hybrid cryptographic primitives

TL;DR The file content is symmetrically encrypted by blocks using AES 256 GCM and a randomly generated key for each file. The key is encrypted using the Ristretto Curve 25519 and prepended to the encrypted file content.

TODO detailed description

Typical usage

The general idea is to stream file content by blocks to and from the disk and encrypt/decrypt it on the fly.

See index.html and index.ts for a working example

Generate a Ristretto Curve 25519 key pair

    const crypto = Cosmian.hybrid_crypto()
    let private_key = crypto.new_private_key()
    let public_key = crypto.get_public_key(private_key)

Encrypt/Decrypt using ECIES

    let array = new Uint8Array([1, 10])
    let encrypted = crypto.encrypt(public_key, array)
    let decrypted = crypto.decrypt(private_key, encrypted)
    // expect(decrypted).toBe(array)

Read a clear text file, encrypt it and save the encrypted file

    // stream the clear text content from the file by block
    let clear_text_stream = Cosmian.clear_text_file_reader(file, EncryptionTransformStream.max_clear_text_length())
    // encrypt a stream of blocks
    let encryption_stream = new EncryptionTransformStream(public_key)
    // save the encrypted content to disk
    const encrypted_file_meta_data = {
        uuid: "12345",
        filename: file.name + ".encrypted",
        mimeType: file.type,
    } as FileMetaData
    let encrypted_writable_stream = await Cosmian.download(encrypted_file_meta_data, () => { console.log("download canceled") })
    // connect all the streams and make the magic happen
    await Promise.all([
        clear_text_stream.pipeTo(encryption_stream.writable),
        encryption_stream.readable.pipeTo(encrypted_writable_stream)
    ])

Read an encrypted file, decrypt it and save the clear text file

    // stream the encrypted content from the file by block
    let encrypted_stream = Cosmian.encrypted_file_reader(file, DecryptionTransformStream.header_length(), DecryptionTransformStream.max_encrypted_length())
    // decrypt a stream of blocks
    let decryption_stream = new DecryptionTransformStream(private_key)
    // save the clear text content to disk
    const decrypted_file_meta_data = {
        uuid: "12345",
        filename: file.name + ".decrypted",
        mimeType: file.type,
    } as FileMetaData
    let decrypted_writable_stream = await Cosmian.download(decrypted_file_meta_data, () => { console.log("download canceled") })
    // connect all the streams and make the magic happen
    await Promise.all([
        encrypted_stream.pipeTo(decryption_stream.writable),
        decryption_stream.readable.pipeTo(decrypted_writable_stream)
    ])

Blind Search

These primitives allow building an encrypted index and querying the index server without the server learning anything about the keys or the queries.

Please note that the index keys are always masked whereas the index values are unmasked on queries (they are masked on additions/updates). If you want to protect the values you must use some deterministic encryption scheme before adding them to the index.

Searchable Encryption Primitives

Based on an implementation of Diana: forward-private searchable encryption scheme based on a constrained PRF.

Reference paper

Simple usage

    // Access a Cosmian application Server managing the index
    const sse = new Cosmian.Sse("http://localhost:9999", private_key)

    // Clear the index, removing all entries
    await sse.drop_index()

    // Add 2 values under index "blah" 
    // and 1 value under index "foo"
    // WARNING: the keys "blah" and "foo" are protected/encrypted
    // however values "aa", "bb", "cc", "dd" will be revealed in clear text (unmasked)
    // server side when a query is performed so you may want to encrypt before
    let upd_1_1: Cosmian.Sse.Entry = {
        index_key: "blah",
        values: ["cc", "aa"]
    }
    let upd_2: Cosmian.Sse.Entry = {
        index_key: "foo",
        values: ["dd"]
    }
    let upd_1_2: Cosmian.Sse.Entry = {
        index_key: "blah",
        values: ["bb"]
    }
    await sse.update([upd_2, upd_1_1, upd_1_2])

    // search all values for "blah"
    // the values are sorted in byte order
    let search_1_1: Cosmian.Sse.Search = {
        index_key: "blah",
        start: 0,
        limit: 0
    }
    let res_1_1 = await sse.search([search_1_1], true)
    assert(res_1_1.length === 1, "invalid number of results")
    assert(res_1_1[0].length === 3, "invalid number of results for search")
    assert(res_1_1[0][0] === "aa", "invalid 1st result")
    assert(res_1_1[0][1] === "bb", "invalid 2nd result")
    assert(res_1_1[0][2] === "cc", "invalid 3rd result")

    // search the 2nd value for entry "blah"
    let search_1_2: Cosmian.Sse.Search = {
        index_key: "blah",
        start: 1,
        limit: 1
    }
    let res_1_2 = await sse.search([search_1_2], true)
    assert(res_1_2.length === 1, "invalid number of results")
    assert(res_1_2[0].length === 1, "invalid number of results for search")
    assert(res_1_2[0][0] === "bb", "invalid result")

    // perform search on 2 index entries at the same time
    let search_1_3: Cosmian.Sse.Search = {
        index_key: "blah",
        start: 1,
        limit: 0
    }
    let search_2_1: Cosmian.Sse.Search = {
        index_key: "foo",
        start: 0,
        limit: 0
    }
    let res_1_3 = await sse.search([search_1_3, search_2_1], true)
    assert(res_1_3.length === 2, "invalid number of results")
    assert(res_1_3[0].length === 2, "invalid number of results for search")
    assert(res_1_3[0][0] === "bb", "invalid 1st result")
    assert(res_1_3[0][1] === "cc", "invalid 2nd result")
    assert(res_1_3[1].length === 1, "invalid number of results for search")
    assert(res_1_3[1][0] === "dd", "invalid 1st result")

    // add one more value to the "blah" entry
    let upd_1_4: Cosmian.Sse.Entry = {
        index_key: "blah",
        values: ["ab"]
    }
    await sse.update([upd_1_4])

    // check it it there at the second position in byte order
    let search_1_4: Cosmian.Sse.Search = {
        index_key: "blah",
        start: 1,
        limit: 1
    }
    let res_1_4 = await sse.search([search_1_4], true)
    assert(res_1_4.length === 1, "invalid number of results")
    assert(res_1_4[0].length === 1, "invalid number of results for search")
    assert(res_1_4[0][0] === "ab", "invalid result")

    // delete 2 values for "blah"
    let delete_1_5: Cosmian.Sse.Entry = {
        index_key: "blah",
        values: ["ab", "bb"]
    }
    await sse.delete([delete_1_5])

    // verify the entries are no more returned
    let search_1_6: Cosmian.Sse.Search = {
        index_key: "blah",
        start: 0,
        limit: 0
    }
    let res_1_6 = await sse.search([search_1_6], true)
    assert(res_1_6.length === 1, "invalid number of results")
    assert(res_1_6[0].length === 2, "invalid number of results for search")
    assert(res_1_6[0][0] === "aa", "invalid 1st result")
    assert(res_1_6[0][1] === "cc", "invalid 2nd result")

Hacking this lib

Hacking this lib requires access to the cryptographic rust code. Cosmian is working on how to make this easily available to developers outside the company.

In this directory, run

npm install

0.2.10

3 years ago

0.2.9

3 years ago

0.2.8

3 years ago

0.2.7

3 years ago

0.2.6

3 years ago

0.2.5

3 years ago

0.2.1

3 years ago

0.2.3

3 years ago

0.2.2

3 years ago

0.2.4

3 years ago

0.2.0

3 years ago

0.1.6

3 years ago

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago