File encryption in Laravel and sudo users - linux

I understand I can encrypt and store the contents of files (csv mainly) using the techniques explained here and here.
However, I am looking for a way to prevent anyone from accessing these files, even users with sudo access to the server. The only one (or group of people) who should be able to access the encrypted files would be those who have a password or encryption key chosen by me. Is this possible?

By default the file will show encrypted data, hence even if the file anyone get cant seen data. however you can also put key protectection using class from Encrypt directly or using spatie crypt
Here LOOK Spatie link
You can also use the default crypt like this
use Illuminate\Encryption\Encrypter;
//Keys and cipher used by encrypter(s)
$fromKey = base64_decode("from_key_as_a_base_64_encoded_string");
$toKey = base64_decode("to_key_as_a_base_64_encoded_string");
$cipher = "AES-256-CBC"; //or AES-128-CBC if you prefer
//Create two encrypters using different keys for each
$encrypterFrom = new Encrypter($fromKey, $cipher);
$encrypterTo = new Encrypter($toKey, $cipher);
//Decrypt a string that was encrypted using the "from" key
$decryptedFromString = $encrypterFrom->decryptString("gobbledygook=that=is=a=from=key=encrypted=string==");
//Now encrypt the decrypted string using the "to" key
$encryptedToString = $encrypterTo->encryptString($decryptedFromString);

Related

How do I validate the Hmac using NodeJS?

I can successfully create an Hmac via NodeJS using the following code:
(slightly altered example from : https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options)
Crypto.createHmac('sha256', Crypto.randomBytes(16))
.update('I love cupcakes')
.digest('hex');
That results in a value like the following (hex-based string Hmac signature):
fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53
How do I use that signature to verify that the data was not altered? (using NodeJS, of course).
My Assumption
I'm assuming there is a method call where you supply the data and the signature and you get a boolean that tells you if the data was altered or not -- or something similar.
Another Solution?
Oh, wait, as I was writing that I started thinking...
Do I need to store the original random bytes I generated (Crypto.randomBytes(16)) and pass them to the receiver so they can just generate the HMac again and verify that the result is the same (fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53)?
If that is true that would be odd, because the parameter for Crypto.randomBytes(16) is named secret (in the official example)*. Seems like that needs to be kept secret??
Please let me know if there is a way to verify the signature on the receiving side & how I do that.
Official Documentation : A Bit Confusing
Here's the function as it is defined in the official docs:
crypto.createHmac(algorithm, key[, options])
In the function definition, you can see the second param is named key.
However, in the example they refer to it as secret
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
.update('I love cupcakes')
.digest('hex');
console.log(hash);
Just posting the answer so if anyone in future sees this they will be able to have the definitive answer.
As the commentor (Topaco) pointed out, the simple answer is that:
The receiver who want wants to validate the Hmac simply needs to use the same key value & data and apply it to the method and retrieve the hash value.
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
.update('I love cupcakes')
.digest('hex');
console.log(hash);
The original Hmac-creating party must provide three things for the verifying party:
data : (could be encrypted data from AES256, for example)
key : original key passed into the createHmac() method -- note: this item is called secret in the sample code by NodeJS (above).
hash :the (clearText) hash which the original creator generated when calling the createHmac() method.
With those three things the verifying party can now call the createHmac() method and determine if the hash they get matches the hash that the original hmac-creating party generated.
Doing this validates that the Data which was sent has not been corrupted or altered.
Additional Note On Key (secret)
I've come back after thinking about the Hmac a bit more.
It is required that both parties know the key (aka secret) but it does not mean that it should be exposed to others.
This must be kept secret (as the code implies) because if a nefarious type knew the value and could alter it, then they could also alter the data and generate a new key (secret) and pass it along as if the original creator sent it along (MITM - man in the middle attack).
So, the point here is that yes, both parties have to know the key (secret) value, but it should not be shared where it might be discovered by nefarious types.
Instead, it will have to be agreed upon or based upon a secret password, etc.

Generating and Storing API Keys - Node js [duplicate]

So with lots of different services around now, Google APIs, Twitter API, Facebook API, etc etc.
Each service has an API key, like:
AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q
All the keys vary in length and the characters they contain, I'm wondering what the best approach is for generating an API key?
I'm not asking for a specific language, just the general approach to creating keys, should they be an encryption of details of the users app, or a hash, or a hash of a random string, etc. Should we worry about hash algorithm (MSD, SHA1, bcrypt) etc?
Edit:
I've spoke to a few friends (email/twitter) and they recommended just using a GUID with the dashes stripped.
This seems a little hacky to me though, hoping to get some more ideas.
Use a random number generator designed for cryptography. Then base-64 encode the number.
This is a C# example:
var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
API keys need to have the properties that they:
uniquely identify an authorized API user -- the "key" part of "API key"
authenticate that user -- cannot be guessed/forged
can be revoked if a user misbehaves -- typically they key into a database that can have a record deleted.
Typically you will have thousands or millions of API keys not billions, so they do not need to:
Reliably store information about the API user because that can be stored in your database.
As such, one way to generate an API key is to take two pieces of information:
a serial number to guarantee uniqueness
enough random bits to pad out the key
and sign them using a private secret.
The counter guarantees that they uniquely identify the user, and the signing prevents forgery. Revocability requires checking that the key is still valid in the database before doing anything that requires API-key authorization.
A good GUID generator is a pretty good approximation of an incremented counter if you need to generate keys from multiple data centers or don't have otherwise a good distributed way to assign serial numbers.
or a hash of a random string
Hashing doesn't prevent forgery. Signing is what guarantees that the key came from you.
Update, in Chrome's console and Node.js, you can issue:
crypto.randomUUID()
Example output:
'4f9d5fe0-a964-4f11-af99-6c40de98af77'
Original answer (stronger):
You could try your web browser console by opening a new tab, hitting CTRL + SHIFT + i on Chrome, and then entering the following immediately invoked function expression (IIFE):
(async function (){
let k = await window.crypto.subtle.generateKey(
{name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
const jwk = await crypto.subtle.exportKey("jwk", k)
console.log(jwk.k)
})()
Example output:
gv4Gp1OeZhF5eBNU7vDjDL-yqZ6vrCfdCzF7HGVMiCs
References:
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey
I'll confess that I mainly wrote this for myself for future reference...
I use UUIDs, formatted in lower case without dashes.
Generation is easy since most languages have it built in.
API keys can be compromised, in which case a user may want to cancel their API key and generate a new one, so your key generation method must be able to satisfy this requirement.
If you want an API key with only alphanumeric characters, you can use a variant of the base64-random approach, only using a base-62 encoding instead. The base-62 encoder is based on this.
public static string CreateApiKey()
{
var bytes = new byte[256 / 8];
using (var random = RandomNumberGenerator.Create())
random.GetBytes(bytes);
return ToBase62String(bytes);
}
static string ToBase62String(byte[] toConvert)
{
const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
BigInteger dividend = new BigInteger(toConvert);
var builder = new StringBuilder();
while (dividend != 0) {
dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
}
return builder.ToString();
}
An API key should be some random value. Random enough that it can't be predicted. It should not contain any details of the user or account that it's for. Using UUIDs is a good idea, if you're certain that the IDs created are random.
Earlier versions of Windows produced predictable GUIDs, for example, but this is an old story.

What's the best approach for generating a new API key?

So with lots of different services around now, Google APIs, Twitter API, Facebook API, etc etc.
Each service has an API key, like:
AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q
All the keys vary in length and the characters they contain, I'm wondering what the best approach is for generating an API key?
I'm not asking for a specific language, just the general approach to creating keys, should they be an encryption of details of the users app, or a hash, or a hash of a random string, etc. Should we worry about hash algorithm (MSD, SHA1, bcrypt) etc?
Edit:
I've spoke to a few friends (email/twitter) and they recommended just using a GUID with the dashes stripped.
This seems a little hacky to me though, hoping to get some more ideas.
Use a random number generator designed for cryptography. Then base-64 encode the number.
This is a C# example:
var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
API keys need to have the properties that they:
uniquely identify an authorized API user -- the "key" part of "API key"
authenticate that user -- cannot be guessed/forged
can be revoked if a user misbehaves -- typically they key into a database that can have a record deleted.
Typically you will have thousands or millions of API keys not billions, so they do not need to:
Reliably store information about the API user because that can be stored in your database.
As such, one way to generate an API key is to take two pieces of information:
a serial number to guarantee uniqueness
enough random bits to pad out the key
and sign them using a private secret.
The counter guarantees that they uniquely identify the user, and the signing prevents forgery. Revocability requires checking that the key is still valid in the database before doing anything that requires API-key authorization.
A good GUID generator is a pretty good approximation of an incremented counter if you need to generate keys from multiple data centers or don't have otherwise a good distributed way to assign serial numbers.
or a hash of a random string
Hashing doesn't prevent forgery. Signing is what guarantees that the key came from you.
Update, in Chrome's console and Node.js, you can issue:
crypto.randomUUID()
Example output:
'4f9d5fe0-a964-4f11-af99-6c40de98af77'
Original answer (stronger):
You could try your web browser console by opening a new tab, hitting CTRL + SHIFT + i on Chrome, and then entering the following immediately invoked function expression (IIFE):
(async function (){
let k = await window.crypto.subtle.generateKey(
{name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
const jwk = await crypto.subtle.exportKey("jwk", k)
console.log(jwk.k)
})()
Example output:
gv4Gp1OeZhF5eBNU7vDjDL-yqZ6vrCfdCzF7HGVMiCs
References:
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey
I'll confess that I mainly wrote this for myself for future reference...
I use UUIDs, formatted in lower case without dashes.
Generation is easy since most languages have it built in.
API keys can be compromised, in which case a user may want to cancel their API key and generate a new one, so your key generation method must be able to satisfy this requirement.
If you want an API key with only alphanumeric characters, you can use a variant of the base64-random approach, only using a base-62 encoding instead. The base-62 encoder is based on this.
public static string CreateApiKey()
{
var bytes = new byte[256 / 8];
using (var random = RandomNumberGenerator.Create())
random.GetBytes(bytes);
return ToBase62String(bytes);
}
static string ToBase62String(byte[] toConvert)
{
const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
BigInteger dividend = new BigInteger(toConvert);
var builder = new StringBuilder();
while (dividend != 0) {
dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
}
return builder.ToString();
}
An API key should be some random value. Random enough that it can't be predicted. It should not contain any details of the user or account that it's for. Using UUIDs is a good idea, if you're certain that the IDs created are random.
Earlier versions of Windows produced predictable GUIDs, for example, but this is an old story.

What is the best way to encrypt stored data in web2py?

I need to encrypt data stored in web2py, more precisely passwords.
This is not about authentication, but more something in the line of a KeePass-like application.
I've seen that is included in web2py, but and M2Secret could easily do that. With M2Secret I can use this:
import m2secret
# Encrypt
secret = m2secret.Secret()
secret.encrypt('my data', 'my master password')
serialized = secret.serialize()
# Decrypt
secret = m2secret.Secret()
secret.deserialize(serialized)
data = secret.decrypt('my master password')
But I would have to include the M2Crypto library in my appliance.
Is there a way to do this with PyMe which is already included with web2py?
By default web2py stores passwords hashed using HMAC+SHA512 so there is nothing for you to do. It is better than the mechanism that you suggest because encryption is reversible while hashing is not. You can change this and do what you ask above but it would not be any more secure than using plaintext (since you would have to expose the encryption key in the app).
Anyway. Let's say you have a
db.define_table('mytable',Field('myfield'.'password'))
and you want to use m2secret. You would do:
class MyValidator:
def __init__(self,key): self.key=key
def __call__(self,value):
secret = m2secret.Secret()
secret.encrypt(value, self.key)
return secret.serialize()
def formatter(self,value):
secret = m2secret.Secret()
secret.deserialize(value)
return (secret.decrypt(self.key),None)
db.mytable.myfield.requires=MyValidator("master password")
In web2py validators are also two way filters.

Coding strategy for securing sensitive data

A web application contains sensitive data of the users. Neither the operator of the web application nor the hosting provider should be able to see this data. Therefore I wanted to store these data in the DB encrypted with the entrance password of the users.
dataInDB = encrypt (rawData, user password)
With this strategy it is however not possible to implement the usual use case for password recovery: Since usually only the hash value of the password is stored by the web app, the application cannot send the old, forgotten password to the user. And with the assignment of a new, coincidental password the encrypted data in the DB are no longer readable.
Is there any other solution ?
A possible solution (I am not responsible for any destruction):
When encrypting sensitive data, don't use the user's password as the key. Rather, derive the key from the user's password (preferably using a standard algorithm such as PBKDF2). Just in case the user forgets their password, you can keep a copy of this derived key (encrypted using a different key derived from the user's answer). If the user forgets their password, they can answer their security question. Only the correct answer will decrypt the original password key (not the original password). This affords you the opportunity to re-encrypt the sensitive information.
I will demonstrate using (Python-esque) pseudo code, but first let's look at a possible table for the users. Don't get caught up in the columns just yet, they will become clear soon...
CREATE TABLE USERS
(
user_name VARCHAR,
-- ... lots of other, useful columns ...
password_key_iterations NUMBER,
password_key_salt BINARY,
password_key_iv BINARY,
encrypted_password_key BINARY,
question VARCHAR,
answer_key_iterations NUMBER,
answer_key_salt BINARY
)
When it comes time to register a user, they must provide a question and answer:
def register_user(user_name, password, question, answer):
user = User()
# The question is simply stored for later use
user.question = question
# The password secret key is derived from the user's password
user.password_key_iterations = generate_random_number(from=1000, to=2000)
user.password_key_salt = generate_random_salt()
password_key = derive_key(password, iterations=user.password_key_iterations, salt=user.password_key_salt)
# The answer secret key is derived from the answer to the user's security question
user.answer_key_iterations = generate_random_number(from=1000, to=2000)
user.answer_key_salt = generate_random_salt()
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The password secret key is encrypted using the key derived from the answer
user.password_key_iv = generate_random_iv()
user.encrypted_password_key = encrypt(password_key, key=answer_key, iv=user.password_key_iv)
database.insert_user(user)
Should the user forget their password, the system will still have to ask the user to answer their security question. Their password cannot be recovered, but the key derived from the password can be. This allows the system to re-encrypt the sensitive information using the new password:
def reset_password(user_name, answer, new_password):
user = database.rerieve_user(user_name)
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The answer key decrypts the old password key
old_password_key = decrypt(user.encrypted_password_key, key=answer_key, iv=user.password_key_iv)
# TODO: Decrypt sensitive data using the old password key
new_password_key = derive_key(new_password, iterations=user.password_key_iterations, salt=user.password_key_salt)
# TODO: Re-encrypt sensitive data using the new password key
user.encrypted_password_key = encrypt(new_password_key, key=user.answer_key, iv=user.password_key_iv)
database.update_user(user)
Of course, there are some general cryptographic principles not explicitly highlighted here (cipher modes, etc...) that are the responsibility of the implementer to familiarize themselves with.
Hope this helps a little! :)
Update courtesy of Eadwacer's comment
As Eadwacer commented:
I would avoid deriving the key directly from the password (limited entropy and changing the password will require re-encrypting all of the data). Instead, create a random key for each user and use the password to encrypt the key. You would also encrypt the key using a key derived from the security questions.
Here is a modified version of my solution taking his excellent advice into consideration:
CREATE TABLE USERS
(
user_name VARCHAR,
-- ... lots of other, useful columns ...
password_key_iterations NUMBER,
password_key_salt BINARY,
password_encrypted_data_key BINARY,
password_encrypted_data_key_iv BINARY,
question VARCHAR,
answer_key_iterations NUMBER,
answer_key_salt BINARY,
answer_encrypted_data_key BINARY,
answer_encrypted_data_key_iv BINARY,
)
You would then register the user as follows:
def register_user(user_name, password, question, answer):
user = User()
# The question is simply stored for later use
user.question = question
# The randomly-generated data key will ultimately encrypt our sensitive data
data_key = generate_random_key()
# The password key is derived from the password
user.password_key_iterations = generate_random_number(from=1000, to=2000)
user.password_key_salt = generate_random_salt()
password_key = derive_key(password, iterations=user.password_key_iterations, salt=user.password_key_salt)
# The answer key is derived from the answer
user.answer_key_iterations = generate_random_number(from=1000, to=2000)
user.answer_key_salt = generate_random_salt()
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The data key is encrypted using the password key
user.password_encrypted_data_key_iv = generate_random_iv()
user.password_encrypted_data_key = encrypt(data_key, key=password_key, iv=user.password_encrypted_data_key_iv)
# The data key is encrypted using the answer key
user.answer_encrypted_data_key_iv = generate_random_iv()
user.answer_encrypted_data_key = encrypt(data_key, key=answer_key, iv=user.answer_encrypted_data_key_iv)
database.insert_user(user)
Now, resetting a user's password looks like this:
def reset_password(user_name, answer, new_password):
user = database.rerieve_user(user_name)
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The answer key decrypts the data key
data_key = decrypt(user.answer_encrypted_data_key, key=answer_key, iv=user.answer_encrypted_data_key_iv)
# Instead of re-encrypting all the sensitive data, we simply re-encrypt the password key
new_password_key = derive_key(new_password, iterations=user.password_key_iterations, salt=user.password_key_salt)
user.password_encrypted_data_key = encrypt(data_key, key=new_password_key, iv=user.password_encrypted_data_key_iv)
database.update_user(user)
Hopefully my head is still functioning clearly tonight...

Resources