Skip to content

Instantly share code, notes, and snippets.

@nolash
Last active May 21, 2018 00:29
Show Gist options
  • Save nolash/2d641c8c931134bfc8f275abd3e51d9d to your computer and use it in GitHub Desktop.
Save nolash/2d641c8c931134bfc8f275abd3e51d9d to your computer and use it in GitHub Desktop.
example on encryption using libsodium kdf key
#include <stdio.h>
#include <sodium.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#define SUBKEYS_COUNT 8
#define SUBKEYS_SIZE crypto_secretstream_xchacha20poly1305_KEYBYTES
#define SUBKEYS_CONTEXT "foo"
#define CHUNK_SIZE 2048
// creates a key and derives subkeys
// if salt file exists it will use it, and result will be the same as the round which saved the salt
// encrypts a file "argon2.dat" (must add manual) with the last subkey, decrypts it with same key and outputs first few bytes of plaintext
int main() {
int r, i, j;
int fd_in, fd_out;
unsigned char key[crypto_box_SEEDBYTES];
unsigned char salt[crypto_pwhash_SALTBYTES];
const char *pass = "foo bar baz xyzzy";
struct stat st;
unsigned char subkeys[SUBKEYS_COUNT][SUBKEYS_SIZE];
unsigned char enc_buf_plain[CHUNK_SIZE];
unsigned char enc_buf_cipher[CHUNK_SIZE+crypto_secretstream_xchacha20poly1305_ABYTES];
unsigned char enc_header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
crypto_secretstream_xchacha20poly1305_state enc_st;
unsigned long long outlen;
unsigned char tag;
// if we have salt, use it
fd_in = open("salt.bin", O_RDONLY, NULL);
if (fd_in < 0) {
randombytes_buf(salt, sizeof(salt));
} else {
r = read(fd_in, salt, sizeof(salt));// better if check length of file
if (r < sizeof(salt)) {
close(fd_in);
return 1;
}
}
close(fd_in);
// create key
r = crypto_pwhash(key, sizeof(key), pass, strlen(pass), salt, crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE, crypto_pwhash_ALG_DEFAULT);
if (r) {
return 1;
}
// save key (of course we never do this in real life)
fd_out = open("key.bin", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
if (fd_out < 0) {
return 2;
}
r = write(fd_out, key, sizeof(key));
if (r != sizeof(key)) {
return 2;
}
close(fd_out);
// save salt
fd_out = open("salt.bin", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
if (fd_out < 0) {
return 3;
}
r = write(fd_out, salt, sizeof(salt));
if (r != sizeof(salt)) {
return 3;
}
close(fd_out);
// create subkeys and show them
for (i = 0; i < SUBKEYS_COUNT; i++) {
crypto_kdf_derive_from_key(subkeys[i], SUBKEYS_SIZE, i, SUBKEYS_CONTEXT, key);
}
for (i = 0; i < SUBKEYS_COUNT; i++) {
printf("key #%d: ", i);
for (j = 0; j < SUBKEYS_SIZE; j++) {
printf("%02x", subkeys[i][j]);
}
printf("\n");
}
// choose the last subkey to encrypt
fd_in = open("argon2.dat", O_RDONLY, NULL);
if (fd_in < 0) {
return 4;
}
fd_out = open("argon2.enc", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
if (fd_out < 0) {
close(fd_in);
return 4;
}
crypto_secretstream_xchacha20poly1305_init_push(&enc_st, enc_header, subkeys[SUBKEYS_COUNT-1]);
r = write(fd_out, enc_header, sizeof(enc_header));
if (r < sizeof(enc_header)) {
close(fd_out);
close(fd_in);
return 5;
}
do {
r = read(fd_in, enc_buf_plain, sizeof(enc_buf_plain));
tag = r ? 0 : crypto_secretstream_xchacha20poly1305_TAG_FINAL;
crypto_secretstream_xchacha20poly1305_push(&enc_st, enc_buf_cipher, &outlen, enc_buf_plain, r, NULL, 0, tag);
write(fd_out, enc_buf_cipher, outlen);
} while (r);
close(fd_out);
close(fd_in);
// decrypt
fd_in = (open("argon2.enc", O_RDONLY, NULL));
r = read(fd_in, enc_header, sizeof(enc_header));
if (crypto_secretstream_xchacha20poly1305_init_pull(&enc_st, enc_header, subkeys[SUBKEYS_COUNT-1])) {
close(fd_in);
return 6;
}
r = read(fd_in, enc_buf_cipher, sizeof(enc_buf_cipher));
if (r<=0) {
close(fd_in);
return 7;
}
r = crypto_secretstream_xchacha20poly1305_pull(&enc_st, enc_buf_plain, &outlen, &tag, enc_buf_cipher, r, NULL, 0);
if (r) {
close(fd_in);
return 8;
}
close(fd_in);
// show a few bytes
*(enc_buf_plain+256)=0;
printf("%s\n", enc_buf_plain);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment