I had tried to do AES256 encryption in Swift3, by using many libraries like CryptoSwift, but couldnt get proper result.
let aes = try AES(key: anykey, iv: "")
let ciphertext = try aes.encrypt(data)
The mode I want to try is as below.
Algorithm: Rijndael-256
MODE: ECB
IV: NULL
if there is mistake in my code, or any better way to AES256 encrypt in Swift3, answer me please.
RNCryptor is a useful framework for AES256 encryption and decryption.
// Encryption
let data ... // Some data you want to encrypt
let password = "0Bfy8q9475jgjjbsu"
let ciphertext = RNCryptor.encryptData(data, password: password)
// Decryption
do {
let originalData = try RNCryptor.decryptData(ciphertext, password: password)
} catch let error {
print("Can not Decrypt With Error: \n\(error)\n")
}
You could also try the CommonCrypto C library which RNCryptor wraps. This comes as standard with XCode. Unfortunately it doesn't have a swift framework setup for it. This project creates a framework for easy use in swift https://github.com/sergejp/CommonCrypto/tree/master/CommonCrypto
You can find example code using the CommonCrypto library here https://github.com/adam-fowler/swift-library/blob/master/data/aes.swift.
Related
I'm trying to make secure keeping users passwords in database. After quick research I decided use ed25519_dalek library.
Important notice:
I plan use this encryption in actix website.
For now steps are simple:
save password in variable,
generate keys,
save secret and public passwords in file(for now),
encrypt password,
save password to database(skipping for now),
I'm stack in third step: saving keys to file.
To be honest I can write passwords to file, but can't read it.
My code below:
use std::io;
use std::io::{BufRead, Write};
use rand::rngs::OsRng;
use ed25519_dalek::{Keypair, PublicKey, Signature, Signer, Verifier};
use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
let mut csprng = OsRng{};
let keypair: Keypair = Keypair::generate(&mut csprng);
let password: &[u8] = b"testing_password123!##$%";
let signature: Signature = keypair.sign(password);
assert!(keypair.verify(&password, &signature).is_ok());
For this moment my code works well. I'm getting signature and looks like values password and signature are the same.
I'm trying to deserialize keys:
let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair.public.to_bytes();
let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes();
let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair.to_bytes();
let signature_bytes: [u8; SIGNATURE_LENGTH] = signature.to_bytes();
After this, I want to save secret key and public key to different files. But for simplify we want to save only secret key.
My steps below:
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
let filename = "keys.txt";
let path = Path::new(filename);
let display = path.display();
let mut file = match File::create(&path) {
Err(why) => panic!("Couldn't create {}: {}", display, why),
Ok(file) => file,
};
match file.write_all(&secret_key_bytes) {
Err(why) => panic!("couldn't write to {}: {}", display, why),
Ok(_) => println!("successfully wrote to {}", display),
};
In this step I can write bytes to a file. But... The key has type [u8;32]. Using cat command showing strange things(I understand why).
But I can't read this file. Bytes can't be read like this.
After this entry is time for my question:
How can I change type of secret key [u8;32] to String or str?
My idea is:
Change datatype to String or str and then save to file.
Or maybe I do something wrong or simply is it better way to do this?
I need little push in right way :)
It is unsafe to encrypt and store passwords in a database. Moreover you are planning to store both public and private keys in files. The program requires it to be kept in reach for authenticating, so it won't be hard for someone to find the files with public and private keys. Anyone who have access to those files can access users' passwords including you.
The workaround is to generate a hash from the password and store it in the database. Hashing is a one way process of generating a string from an input string such that the inverse operation is impossible. So,the hash of the user input and the hash in the database is matched to authorize the user. There are a bunch of hashing functions available in RUST including the SHA-2 family hashing functions.
It is still insecure if you are just hashing the passwords and saving them in the database since the hashes of most common passwords and almost all possible words are already available in datasets named hash dictionaries and by using that, anyone who have access to your database can find the password. This technique is called dictionary attack. To prevent it, you can make the input string larger by concatenating with some random characters (salt) with the user input and
store the hash and the salt in the database.
I am using eccrypto library in javascript for encryption using the ECIES algorithm (curve- secp256k1). The cipher generated by encryption in JS code could not be decrypted in Kotlin.
Here is the Javascript code.
var eccrypto = require("eccrypto");
eccrypto.encrypt(publicKeyA, Buffer.from("Sic Mundus Creatus Est")).then(function(encrypted) {
val ciphertext = encrypted.ciphertext
//the hex encoded ciphertext is then sent to the server
}
Here is the decryption code for kotlin
val cipherBytes = DatatypeConverter.parseHexBinary(ciphertext)
val cipher: Cipher = Cipher.getInstance("ECIES", "BC")
cipher.init(Cipher.DECRYPT_MODE, privateKeyA)
print( cipher.doFinal(cipherBytes) )
With this code for decryption, I get an Bad Block Exception.
However, if I just do encryption and decryption using Java, there is no problem. Also, encryption and decryption both in Javascript also work fine.
Is there anything I am missing?
I found the solution (or say figured out the actual issue). Hope it helps future devs:
The mismatch in encryption/decryption between javascript and java implementation is because those implementations are using different parameters of the hash algorithm and AES encryption.
ECIES implementation in Java using BouncyCastle has a crappy implementation. It uses AES with 128 bits, does not use a secure hash algorithm, no robust check for MAC, and has very little test cases.
As a workaround, I now use a custom written ECIES implementation for Java which uses SHA-512 for the hash, AES encryption (using 256 bits key and AES/CBC/PKCS7Padding mode). This new implementation is what eccrypto javascript library engine uses under the hood. Now, they work fine!
Your comment 'Encrypting the same message using the same public key in both environment gives different cipher messages' does not prove a difference between values. I encrypted 10 times the same message '123' with my public key and got 10 times a different encrypted value.
This is due to a random element in the (internal) encryption function:
ciphertext: 0444a9e31cf1f8f7cabcf2a6562622ce2ee1c38bcdf9938fa48401b34fbeae7ea70c9ad1bd16343a3632ef9011ba6081a7df47ed2ca9904bf0f97febdd18f1b5da9315f744a68c87deee353b481cfbe90a49462403550e3a
ciphertext: 04e1970f415cccb62dc61de534bd61ce9627e9b0e857f6270c20b202f3e62a789979d7c9ca893d85f65f00f5462a29cb986764e34fefb8f5c5ce8f0e9700ddf777b616539ec4e860bad4cac04f8cd3b29c61513cb68a1c9b
ciphertext: 04b07bfbfa53e17446ac8ebaf6af53056274ff4e104bfe26da6176aab390d521429971c151f31a1af4b0240703d4b75a81136b22695798b1ad1cf272e842f5e60ba931972e6868ca54301ec6585ff503cfab76f69ad3beb0
ciphertext: 041d90bcfa34af06559c5f482d06a684492001bb3bd52dc2e9f2eb31cd2de27e595fad3178c0f65d3cd160e0444ae6d9cbfbd2a1e12e21525057d79b8ea24fed572426e3fdeba4a298c17fc481acb66db7b0c8f1d0d0701d
ciphertext: 04a440a994dc0a5f712b1190e1dc0bfff15c053e4a03dc3c74c0cfc965a2da5ed6d668a52b4ae1e320b5ed068fc338e2076f2bc68f156fb79d67daf74ab21c4036a23bebcca007417d5c8ed486750dd37b3f495de92312aa
ciphertext: 04033bfaa2fb90c667ca25e77abba6cdc8e6c601ebb5bf836456c810abe54a4d426b3e52477a8b97f1115905d0babbdda572d9294532d7eda032f6fc98a588c77b00b7bebfe1fe1f4319f3aa0b1776c6da02d9f24baa98c2
ciphertext: 047a1aa7e82084af63cdf76ad0bdd21865d38fdee7fa8902dbf5c0e4840c7209c9cb249698802313c83d22fc8e18b376012888ee0878d4e8c186c241b648180613b1ee460bf9eef5c9a6fab15541ae4bc16dd9f98a10c940
ciphertext: 04dbababe30bd8013bd74f846ed2f1bd818e5b826b59b9b6c6336a62e2e373e82e7f80d2a2fbc3094435e61a53325aba6585047af6bfa593260afc6e5ee737783a8dbbc60d3f99277eea95ed2671d2a81d369602388b7cb0
ciphertext: 04eb52c8d946bfd1d84b27858f78d174bf77509058d10d6bfe11ee5f6553b1c571b3c9c7389b08e596735342584c2be43f5ef4e6952d3db7b5239d00b2c7d22f1ca9e588a8f6dc5c8274d97d18999c4a88702d12b9d56ea6
ciphertext: 04808530ee927d5445a1e8f7a06b6bd8c1457cbf89ea6a75e2a28fd8899e06e8ccc5fab8b45536610a79a50ebf3ca1ed5fafb782fe483165fdc483c7e2e3c3724409d539cdbf586f090b783647d791f33ddfa8e2ba29e328
I have searched and found examples of AES with the default 256 key size and find it worked already. But when I want to use 128 key size, there is little information.
I have extracted code from the aes test from CryptoJS:
var C = CryptoJS;
var plainText = '00112233445566778899aabbccddeeff';
var key = '000102030405060708090a0b0c0d0e0f';
var encryptedText = C.AES.encrypt(C.enc.Hex.parse(plainText), C.enc.Hex.parse(key), { mode: C.mode.ECB, padding: C.pad.NoPadding }).ciphertext.toString();
console.log(encryptedText);
var decryptedText = C.AES.decrypt(C.lib.CipherParams.create({ ciphertext: C.enc.Hex.parse(encryptedText) }), C.enc.Hex.parse(key), { mode: C.mode.ECB, padding: C.pad.NoPadding }).toString();
console.log(decryptedText);
This worked, but if I want to use a different plain text like 'Hello World' then it failed. Also what if I want to use a password like 'my-key-001'? As I have read that CryptoJS expect to use 256 key size if I pass a password.
Your help is much appreciated.
This worked, but if I want to use a different plain text like 'Hello World' then it failed.
You have used the noPadding and that is the issue. The example is multiple of 16-byte that causes no problem, however your next plaintext is not. You can use noPadding if
your message is an exact multiple of the block size, though still not recommended.
you want to pad the message yourself, probably that is you want to test a new padding scheme that we don't see in your code.
You should you padding like
padding: CryptoJS.pad.Pkcs7
As I have read that CryptoJS expect to use 256 key size if I pass a password.
CryptoJS supports AES-128, AES-192, and AES-256. According to your key size it will select the key variants. If you use a password it will generate a 256-bit size. That is %40 times slower than AES-128 since it requires 14 rounds. However use a good password, see below.
Also what if I want to use a password like 'my-key-001'?
A password with high entropy is important otherwise the attackers can be successful by testing passwords. The key generation cannot increase entropy. Therefore you need a good way to generate high entropy passwords like using diceware.
How to encrypt in AES using CryptoJS with key size of 128?
Just provide a 128-bit key.
Does AES-128 has 128-bit security
Any block cipher, not only AES, has vulnerable to multi-target attacks. In that case it is not providing 128-bit security. Therefore you should use 192 or 256-bit keys.
For a more detailed see this question Has AES-128 been fully broken?
mode: C.mode.ECB
The ECB mode of operations is not advised, it is insecure and it leaks pattern. You should use modern encryption modes like AES-GCM which provides you not confidentiality but also, integrity and authentication.
While using GCM mode, make sure that you never use the same IV/nonce again under the same key. AES-GCM uses CTR mode for encryption and under the same key if the IV/nonce repeated then crig-dragging is possible. Also, it can leak the authentication key.
I have seen the examples but I'm hoping to run this by other programmers. For encryption within my window forms app, I am generating two random numbers and saving them in an SQL Server table like thus:
OPEN SYMMETRIC KEY SymmetricKeyName DECRYPTION BY CERTIFICATE CertificateName;
insert into keyfile(encrypted_key1, encrypted_key2) values
(EncryptByKey(Key_GUID('SymmetricKeyName'), **Key1**),
EncryptByKey(Key_GUID('SymmetricKeyName'), **Key2**))
Then I am using the keys to encrypt a file using AES-256 as follows:
var key = new Rfc2898DeriveBytes(**Key1, Key2**, 1000);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
using (var output = File.Create(outputFile))
{
using (var crypto = new CryptoStream(output, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
using (var input = File.OpenRead(inputFile))
{
input.CopyTo(crypto);
}
}
}
etc.
In order to perform decryption both keys that were used to encrypt the file are required. Decryption is possible through software requiring two authenticated users. The keys change every day. The data and the database are sufficiently physically secure. The key table is in a separate database from the certificate.
The question is: Does this secure the data enough to not be readily be decrypted and, if now, why not and what changes might you suggest?
The problem here is that there is a high probability that anyone that is able to obtain the file is also able to obtain the data in the database (which includes the key). Once the data is compromised, it doesn't matter how often you change the key since the attacker would have a copy of the file encrypted with the key that matches it.
Common solutions to this problem are to use an external Hardware Security Module or something like a TPM.
Here is a very useful and related post that enumerates several options.
As suggested by others, you can store the key on a USB, alternatively a network share. However if on a network share you might need to change the Service Logon to an account with access to the network share.
"SYMMETRIC KEY" might be an issue here. They are similar to a xor operation, the same key works to both encrypt and decrypt.
For a 'cooler' method, use ASYMMETRIC keys instead, then the database can keep the 'how to encrypt' half, while your application can have the 'how to decrypt' half. It's a lot of effort, but "not even the DBAs can see the secret data" is a cool feature.
I have two separated applications, one written in Java and other in Erlang.
Both applications send messages to each other in String format, and those messages are encrypted in the Java app and need to be decrypted in the Erlang app.
The problem is this:
I'm using RSA public/private keys to do the encryption/decryption.
If I encrypt the data and decrypt all inside the my Erlang code, everything is fine. But, I'm not able to decrypt the string coming from my java endpoint.
Here's a simple test I'm doing:
PrivKey = "-----BEGIN RSA PRIVATE KEY----- ...",
% Data is the string I receive from Java
Data = "s013aA/SGN2iGYEbEIXXKvJiipqisRVfVEDneL8npRgThTHxTnYZESzVfCF463phPZyo5aOozisU7pwDdGKXgY8aqYZC+a3uES5muTb2RrzJ17yYku+g4S44vgIwZ9EyustZafNVGEYfgbWOYaPP/q5k683uR+MRHVqp6UbqMok=",
[PrivEntry] = public_key:pem_decode(list_to_binary(PrivKey)),
Priv = public_key:pem_entry_decode(PrivEntry),
BinData = iolist_to_binary(Data),
public_key:decrypt_private(Data, Priv).
Executing this code generates an error like this:
** exception error: decrypt_failed
I think the problem is in the format of BinData, but I couldn't find any place saying how I encode a string to pass to decrypt_private function.
Does anyone knows how to do this? This seems simple, but is taking me a lot of time to figure out.
Thanks.
After digging a little bit more, I found the answer!
I needed to decode my string into a base64 binary.
PrivKey = "-----BEGIN RSA PRIVATE KEY----- ...",
% Data is the string I receive from Java
Data = "s013aA/SGN2iGYEbEIXXKvJiipqisRVfVEDneL8npRgThTHxTnYZESzVfCF463phPZyo5aOozisU7pwDdGKXgY8aqYZC+a3uES5muTb2RrzJ17yYku+g4S44vgIwZ9EyustZafNVGEYfgbWOYaPP/q5k683uR+MRHVqp6UbqMok=",
[PrivEntry] = public_key:pem_decode(list_to_binary(PrivKey)),
Priv = public_key:pem_entry_decode(PrivEntry),
BinData = base64:decode(Data), %<-- THIS IS THE MAGIC
public_key:decrypt_private(BinData, Priv).
Hope this helps other people.