File : core/lib/DataEncryptor.js

1
/*
2
Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/
3
4
This  program is free software;
5
you can redistribute it and/or modify it under the terms of the
6
GNU General Public License as published by the Free Software Foundation;
7
either version 3 of the License, or any later version.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
15
*/
16
/*
17
Changes:
18
    - v4.0.0:
19
        - created from v3.6.0
20
Doc reviewed 202208
21
 */
22
23
/* ------------------------------------------------------------------------------------------------------------------------- */
24
/**
25
This class is used to encrypt an decrypt data with a password
26
*/
27
/* ------------------------------------------------------------------------------------------------------------------------- */
28
29
class DataEncryptor {
30
31
    /**
32
    Salt to be used for encoding and decoding operations.
33
    @type {String}
34
    */
35
36
    #salt;
37
38
    /* eslint-disable no-magic-numbers */
39
40
    /**
41
    Call the importKey() method of the SubtleCrypto interface
42
    @param {Uint8Array} pswd The password to use, encode with TextEncoder.encode ( )
43
    @return {Promise} a Promise that fulfills with the imported key as a CryptoKey object
44
    */
45
46
    #importKey ( pswd ) {
47
        return window.crypto.subtle.importKey (
48
            'raw',
49
            pswd,
50
            { name : 'PBKDF2' },
51
            false,
52
            [ 'deriveKey' ]
53
        );
54
    }
55
56
    /**
57
    Call the deriveKey() method of the SubtleCrypto interface
58
    @param {CryptoKey} masterKey the CryptoKey returned by the onOk handler of the Promise returned by #importKey
59
    @param {String} salt The salt to use
60
    @return {Promise} a Promise which will be fulfilled with a CryptoKey object representing the secret key derived
61
    from the master key
62
    */
63
64
    #deriveKey ( masterKey, salt ) {
65
        return window.crypto.subtle.deriveKey (
66
            {
67
                name : 'PBKDF2',
68
                salt : new window.TextEncoder ( ).encode ( salt ),
69
                iterations : 1000000,
70
                hash : 'SHA-256'
71
            },
72
            masterKey,
73
            {
74
                name : 'AES-GCM',
75
                length : 256
76
            },
77
            false,
78
            [ 'encrypt', 'decrypt' ]
79
        );
80
    }
81
82
    /**
83
    Call the decrypt() method of the SubtleCrypto interface
84
    @param {CryptoKey} decryptKey The key to use for decryption
85
    @param {Uint8Array} data The data to decode
86
    @return {Promise} a Promise which will be fulfilled with the decrypted data as a Uint8Array.
87
    Use TextDecoder.decode ( ) to transform to string
88
    */
89
90
    #decrypt ( decryptKey, data ) {
91
        return window.crypto.subtle.decrypt (
92
            {
93
                name : 'AES-GCM',
94
                iv : new Uint8Array ( data.slice ( 0, 16 ) )
95
            },
96
            decryptKey,
97
            new Uint8Array ( data.slice ( 16 ) )
98
        );
99
    }
100
101
    /**
102
    Call the encrypt() method of the SubtleCrypto interface
103
    @param {CryptoKey} encryptKey The key to use for encryption
104
    @param {Uint8Array} ivBytes A Uint8Array with random values used for encoding
105
    @param {Uint8Array} data the data to encode transformed to a Uint8Array with TextEncoder.encode ( )
106
    @return {Promise} a Promise which will be fulfilled with the encrypted data as a Uint8Array
107
    */
108
109
    #encrypt ( encryptKey, ivBytes, data ) {
110
        return window.crypto.subtle.encrypt (
111
            {
112
                name : 'AES-GCM',
113
                iv : ivBytes
114
            },
115
            encryptKey,
116
            data
117
        );
118
    }
119
120
    /**
121
    The constructor
122
    @param {String} salt Salt to be used for encoding and decoding operations. If none, a default value is provided.
123
    */
124
125
    constructor ( salt ) {
126
        this.#salt = salt || 'Tire la chevillette la bobinette cherra. Le Petit Chaperon rouge tira la chevillette.';
127
        Object.freeze ( this );
128
    }
129
130
    /* eslint-disable max-params */
131
132
    /**
133
    This method encrypt data with a password
134
    @param {Uint8Array} data The data to encrypt. See TextEncoder ( ) to transform string to Uint8Array
135
    @param {function} onOk A function to execute when the encryption succeeds
136
    @param {function} onError A function to execute when the encryption fails
137
    @param {Promise} pswdPromise A Promise that fullfil with a password. Typically a dialog...
138
    */
139
140
    encryptData ( data, onOk, onError, pswdPromise ) {
141
        let ivBytes = window.crypto.getRandomValues ( new Uint8Array ( 16 ) );
142
        pswdPromise
143
            .then ( pswd => this.#importKey ( pswd ) )
144
            .then ( deriveKey => this.#deriveKey ( deriveKey, this.#salt ) )
145
            .then ( encryptKey => this.#encrypt ( encryptKey, ivBytes, data ) )
146
            .then (
147
                cipherText => {
148
                    onOk (
149
                        new Blob (
150
                            [ ivBytes, new Uint8Array ( cipherText ) ],
151
                            { type : 'application/octet-stream' }
152
                        )
153
                    );
154
                }
155
            )
156
            .catch ( onError );
157
    }
158
159
    /**
160
    This method decrypt data with a password
161
    @param {Uint8Array} data The data to decrypt. See TextDecoder ( ) to transform Uint8Array to string
162
    @param {function} onOk A function to execute when the decryption succeeds
163
    @param {function} onError A function to execute when the decryption fails
164
    @param {Promise} pswdPromise A Promise that fullfil with a password. Typically a dialog...
165
    */
166
167
    decryptData ( data, onOk, onError, pswdPromise ) {
168
        pswdPromise
169
            .then ( pswd => this.#importKey ( pswd ) )
170
            .then ( deriveKey => this.#deriveKey ( deriveKey, this.#salt ) )
171
            .then ( decryptKey => this.#decrypt ( decryptKey, data ) )
172
            .then ( onOk )
173
            .catch ( onError );
174
    }
175
    /* eslint-enable max-params */
176
    /* eslint-enable no-magic-numbers */
177
}
178
179
export default DataEncryptor;
180
181
/* --- End of file --------------------------------------------------------------------------------------------------------- */
182