This module implement a shared secret encryption/description engine that can be used to successfully encrypt data that should be readable by different actors.
As a convenience, this module also has a Fecade helping to manage the 2FA authentication devices:
As a further convenience also a function to transmit a CredentialRecord (with
password or not) as a JWT token is provided. This feature is based on the
following library:
- Go 1.14 of newer
You can run the unit tests with:
make test
and benchmarks with:
make benchmark
This system is secure as the passwords choosen by users are, since the master key is encrypted using the password of the user.
- Password are stored using a PBKDF2 scheme using HMAC-SHA-1 hash
- Data is encrypted using an AES-256 scheme
A crypto space is composed by:
- as a set of encrypted data
- a set of actors.
Every actor in the crypto space can read the encrypted data. Actors in different crypto space can't search each other data.
Each crypto space has his own master key, and a master key can be generated
using the function GenerateMasterKey in bitbucket.com/leonardoce/pkg/models.
The generation of the master key is the first step needed to use this library, and the generated master key should not be stored in the database.
The master key can be recovered from each credential in the crypto space or directly in the bootstrap phase.
The master key must not be stored in the database or sent to other servers.
What follows is a set of examples on how a crypto space can be used.
For every credential allowing access to the crypto space a CredentialRecord
defined in bitbucket.com/leonardoce/pkg/models must be created and stored
persistently.
To create a new user we can use the master key from the bootstrap of the crypto space, or recover a master key from a user with verified credentials (see the "Login" section).
To create a new CredentialRecord with a master key, you can use the
NewCredentialRecord function of bitbucket.com/leonardoce/pkg/models with the
first time password. The resulting CredentialRecord must the stored in the
persistent data storage.
Given a CredentialRecord we can verify if a password supplied by the user is
good, and if is, we can extract the master key. This can be done via the member
functions of CredentialRecord. Look at:
IsPasswordValidRecoverMasterKey
A new session can be viewed as a new CredentialRecord whose username and
passwords are randomly generated and linked to a real user.
The username can be stored in the database, and the password can be sent to the client, who will send it back to the server for every request together with the username.
That credential can be than used to recover the master key.
If you have the master key, you can use it to encrypt or decrypt data. Look at
the following functions in bitbucket.com/leonardoce/pkg/models:
EncryptDecrypt
Remember that the previous functions don't have any protection against a wrong key. That means that wrong data will be returned if the master key is not valid.
The encryption and the decryption functions are not time consuming at all, at least on hardware which directly implements the AES encryption (this is all modern servers and laptops, too).
The password checking functions are expensive: checking a password takes 8ms on my laptop. We could evaluate to replace the currently used algorithm with a faster one, if we want.
The facade provided can be used to implement a 2FA authentication scheme. For every user the TOTP secret must be created and stored.
You can generate a secret using the CreateRandomSecret function.
Given a secret, the NewTOTP function can be used to bootstrap the engine and,
the first time, a PNG can be generated and shown to the user. Look at the
GetQRCodeAsPNG function for that.
When the mobile device is configured, you can check if the password provided by
the user is good using the Verify function of the TOTP engine.
The proposed Makefile will build a bin/otp binary, from cmd/opt, which can
be used to test the OTP feature.
Invoking bin/otp will produre a qr.png file which can be used to configure
the authentiation on a mobile phone App such as Authy.
bin/otp -check 'codehere' can be used to check if the OTP proposed by the App
is valid or not.
The code in cmd/otp/main.go can be used as a further reference.
If you are creating sessions for your users, those sessions could be interpreted as temporary credentials for the crypto space. A session can be created using the master key decoded for a certain user. Then:
- the username and the password could be sent to the user in a JWT token;
- the username can be stored in the server database.
JWT tokens as implemented by this package are signed with an RSA encryption scheme. This means that a key pair is needed on the server to successfully generate tokens.
To generate a key pair you can use the following commands:
$ openssl genrsa -out signing.key 4096
$ openssl rsa -in signing.key -pubout -outform PEM -out signing.pub
The JWT subsystem can be created with the function named CreateEngine in
bitbucket.org/leonardoce/idcrypt/pkg/jwt. You will need the key pair and also
to choose a token duration.
Tokens can be generated via CreateJWT and decoded and validated via
ParseJWT.