Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Текст программы.doc
Скачиваний:
2
Добавлен:
07.07.2019
Размер:
172.03 Кб
Скачать

2

Р.П.408112-0 ХХ 01

УТВЕРЖДЕНО

Р.П.408112-07 12 01-лу

Драйвер файловой системы с шифрованием т екст программы

Р.П.408112-07 12 01

Аннотация

В настоящем документе приведен текст программы «CryptoFS», предназначенной для прозрачного шифрования файлов. Текст программы реализован в виде символической записи на исходном языке. Исходным языком данной разработки является ANSI C. Среда разработки – NetBeans. Компилятор – GCC.

Программа обеспечивает возможность выполнения перечисленных ниже функций:

  • загрузка открытых и/или закрытых ключей;

  • передача подсистеме FUSE параметров, необходимых для монтирования заданной файловой системы;

  • переопределение набора функций, реализующих операции с файлами, каталогами и атрибутами файлов;

  • реализация шифрования файлов с использованием симметричного алгоритма AES и ассиметричного алгоритма RSA.

Содержание

Текст программы 4

Лист регистрации изменений 14

Текст программы

#define FUSE_USE_VERSION 26

#define _FILE_OFFSET_BITS 64

#define _GNU_SOURCE

#include <fuse.h>

#include <stdio.h>

#include <string.h>

#include <errno.h>

#include <fcntl.h>

#include <unistd.h>

#include <openssl/rsa.h>

#include <openssl/pem.h>

#include <openssl/aes.h>

#include <openssl/err.h>

#include <openssl/ssl.h>

#include <openssl/rand.h>

#include <dirent.h>

struct public_key {

RSA * key;

unsigned char fingerprint[20];

uid_t owner;

gid_t owner_group;

};

static char mount_dir[256];

static RSA * private_key = NULL;

static unsigned char private_key_fingerprint[20];

static struct public_key * public_keys = NULL;

static int public_keys_count = 0;

void get_fingerprint(RSA * key, unsigned char * fingerprint) {

SHA_CTX finger;

SHA1_Init(&finger);

int size = BN_num_bytes(key->n);

unsigned char * num = malloc(size);

BN_bn2bin(key->n, num);

SHA1_Update(&finger, num, size);

size = BN_num_bytes(key->e);

BN_bn2bin(key->e, num);

SHA1_Update(&finger, num, size);

SHA1_Final(fingerprint, &finger);

free(num);

}

int check_permissions(int fd) {

struct stat f_stat;

if (fstat(fd, &f_stat) == -1) {

return -errno;

}

if (S_ISDIR(f_stat.st_mode)) {

return 0;

}

char fingerprint[20];

if (pread(fd, fingerprint, 20, 0) < 20) {

return -ENOENT;

}

if (private_key == NULL ||

memcmp(fingerprint, private_key_fingerprint, 20) != 0) {

return -EACCES;

}

return 0;

}

static int crypto_open(const char * path, struct fuse_file_info * fi) {

char * full_path = malloc(strlen(mount_dir) + strlen(path) + 2);

sprintf(full_path, "%s%s", mount_dir, path);

int mode = fi->flags;

if ((mode & 0x3) == O_WRONLY) {

mode = (mode & (~ 0x3)) | O_RDWR;

}

mode &= ~ O_APPEND;

int fd = open(full_path, mode);

free(full_path);

if (fd == -1) {

return -errno;

}

int rc;

if ((rc = check_permissions(fd)) != 0) {

close(fd);

return rc;

}

fi->fh = fd;

return 0;

}

static int crypto_release(const char * path, struct fuse_file_info * fi) {

return close(fi->fh);

}

static int crypto_mknod(const char * path, mode_t mode, dev_t rdev) {

RSA * key = private_key;

unsigned char * key_fingerprint = private_key_fingerprint;

if (private_key == NULL) {

int no_key = 1;

int i;

uid_t my_uid = getuid();

for (i = 0; i < public_keys_count; i++) {

if (public_keys[i].owner == my_uid) {

no_key = 0;

key = public_keys[i].key;

key_fingerprint = public_keys[i].fingerprint;

break;

}

}

if (no_key) {

return -EACCES;

}

}

if (!S_ISREG(mode)) {

return -EPERM;

}

char * full_path = malloc(strlen(mount_dir) + strlen(path) + 2);

sprintf(full_path, "%s%s", mount_dir, path);

if (mknod(full_path, mode, rdev) == -1) {

free(full_path);

return -errno;

}

int fd = open(full_path, O_WRONLY);

free(full_path);

if (fd == -1) {

return -errno;

}

write(fd, key_fingerprint, 20);

write(fd, "\0", 1);

unsigned char AES_key[32];

int size = RSA_size(key);

unsigned char * AES_key_encrypted = malloc(size);

RAND_bytes(AES_key, 32);

RSA_public_encrypt(32, AES_key, AES_key_encrypted, key, RSA_PKCS1_OAEP_PADDING);

write(fd, AES_key_encrypted, size);

free(AES_key_encrypted);

close(fd);

return 0;

}

static int crypto_read(const char * path, char * buf, size_t size, off_t offset, struct fuse_file_info * fi) {

size_t len;

struct stat f_stat;

if (fstat(fi->fh, &f_stat) == -1) {

return -errno;

}

char end_pad_size;

if (pread(fi->fh, &end_pad_size, 1, 20) < 1){

return -ENODATA;

}

int header_size = 21 + RSA_size(private_key);

len = f_stat.st_size;

if (header_size + end_pad_size > len) {

return -ENODATA;

}

len -= header_size;

if ((len & 0xF) != 0) {

return -ENODATA;

}

len -= end_pad_size;

if (offset >= len) {

return 0;

}

if (offset + size > len) {

size = len - offset;

}

int key_size = RSA_size(private_key);

unsigned char * AES_key = malloc(key_size);

unsigned char * AES_key_encrypted = malloc(key_size);

if (pread(fi->fh, AES_key_encrypted, key_size, 21) < key_size){

return -ENODATA;

}

if (RSA_private_decrypt(key_size, AES_key_encrypted, AES_key, private_key, RSA_PKCS1_OAEP_PADDING) != 32) {

return -ENODATA;

}

AES_KEY decrypt_key;

AES_set_decrypt_key(AES_key, 256, &decrypt_key);

memset(AES_key, 0, key_size);

free(AES_key);

free(AES_key_encrypted);

unsigned char file_block[16];

unsigned char decrypted_file_block[16];

int block_offset = (offset & (~ 0xF)) + header_size;

size_t read_size = 0;

int start_offset = offset & 0xF;

while (read_size < size) {

if (pread(fi->fh, file_block, 16, block_offset) < 16){

break;

}

AES_decrypt(file_block, decrypted_file_block, &decrypt_key);

int read_block_size = 16 - start_offset;

if (read_size + read_block_size > size) {

read_block_size = size - read_size;

}

memcpy(buf + read_size, decrypted_file_block + start_offset, read_block_size);

read_size += read_block_size;

block_offset += 16;

start_offset = 0;

}

return read_size;

}

static int crypto_write(const char * path, const char * buf, size_t size, off_t offset, struct fuse_file_info * fi) {

size_t len;

struct stat f_stat;

if (fstat(fi->fh, &f_stat) == -1) {

return -errno;

}

char end_pad_size;

if (pread(fi->fh, &end_pad_size, 1, 20) < 1){

return -ENODATA;

}

int header_size = 21 + RSA_size(private_key);

len = f_stat.st_size;

if (header_size + end_pad_size > len) {

return -ENODATA;

}

len -= header_size;

if ((len & 0xF) != 0) {

return -ENODATA;

}

len -= (end_pad_size > 0 ? 16 : 0);

int key_size = RSA_size(private_key);

unsigned char * AES_key = malloc(key_size);

unsigned char * AES_key_encrypted = malloc(key_size);

if (pread(fi->fh, AES_key_encrypted, key_size, 21) < key_size){

return -ENODATA;

}

if (RSA_private_decrypt(key_size, AES_key_encrypted, AES_key, private_key, RSA_PKCS1_OAEP_PADDING) != 32) {

return -ENODATA;

}

AES_KEY decrypt_key;

AES_KEY encrypt_key;

AES_set_decrypt_key(AES_key, 256, &decrypt_key);

AES_set_encrypt_key(AES_key, 256, &encrypt_key);

memset(AES_key, 0, key_size);

free(AES_key);

free(AES_key_encrypted);

unsigned char file_block[16];

unsigned char encrypted_file_block[16];

int block_offset = offset & (~ 0xF);

size_t write_size = 0;

int start_offset = offset & 0xF;

while (write_size < size) {

int write_block_size = 16 - start_offset;

if (write_size + write_block_size > size) {

write_block_size = size - write_size;

}

if (block_offset < len + end_pad_size && (start_offset > 0 || write_size + write_block_size > size)) {

if (pread(fi->fh, encrypted_file_block, 16, block_offset + header_size) < 16){

break;

}

AES_decrypt(encrypted_file_block, file_block, &decrypt_key);

}

if (block_offset >= len) {

end_pad_size = (char)(16 - write_block_size - start_offset);

}

memcpy(file_block + start_offset, buf + write_size, write_block_size);

AES_encrypt(file_block, encrypted_file_block, &encrypt_key);

if (pwrite(fi->fh, encrypted_file_block, 16, block_offset + header_size) < 16){

break;

}

if (pwrite(fi->fh, &end_pad_size, 1, 20) < 1){

break;

}

write_size += write_block_size;

block_offset += 16;

start_offset = 0;

}

return write_size;

}

static int crypto_chown(const char * path, uid_t uid, gid_t gid) {

char * full_path = malloc(strlen(mount_dir) + strlen(path) + 2);

sprintf(full_path, "%s%s", mount_dir, path);

struct stat f_stat;

stat(full_path, &f_stat);

int fd = open(full_path, O_RDWR);

free(full_path);

if (fd == -1) {

return -errno;

}

int rc;

if ((rc = check_permissions(fd)) != 0) {

close(fd);

return rc;

}

int old_key_size = RSA_size(private_key);

if (((f_stat.st_size - 21 - old_key_size) & 0xF) != 0) {

return -ENODATA;

}

int i;

for (i = 0; i < public_keys_count; i++) {

if (public_keys[i].owner == uid) {

unsigned char file_block[16];

unsigned char decrypted_file_block[16];

pwrite(fd, public_keys[i].fingerprint, 20, 0);

unsigned char * old_AES_key = malloc(old_key_size);

unsigned char new_AES_key[32];

int new_key_size = RSA_size(public_keys[i].key);

unsigned char * old_AES_key_encrypted = malloc(old_key_size);

unsigned char * new_AES_key_encrypted = malloc(new_key_size);

if (pread(fd, old_AES_key_encrypted, old_key_size, 21) < old_key_size) {

return -ENODATA;

}

if (RSA_private_decrypt(old_key_size, old_AES_key_encrypted, old_AES_key, private_key, RSA_PKCS1_OAEP_PADDING) != 32) {

return -ENODATA;

}

RAND_bytes(new_AES_key, 32);

AES_KEY decrypt_key;

AES_KEY encrypt_key;

AES_set_decrypt_key(old_AES_key, 256, &decrypt_key);

AES_set_encrypt_key(new_AES_key, 256, &encrypt_key);

int j;

if (old_key_size >= new_key_size) {

j = 21;

} else {

j = f_stat.st_size - old_key_size - 16;

}

while (1) {

if (old_key_size >= new_key_size) {

if (j + old_key_size >= f_stat.st_size) {

break;

}

} else if (j < 21) {

break;

}

if (pread(fd, file_block, 16, j + old_key_size) < 16) {

return -ENODATA;

}

AES_decrypt(file_block, decrypted_file_block, &decrypt_key);

AES_encrypt(decrypted_file_block, file_block, &encrypt_key);

if (pwrite(fd, file_block, 16, j + new_key_size) < 16) {

return -ENODATA;

}

if (old_key_size >= new_key_size) {

j += 16;

} else {

j -= 16;

}

}

RSA_public_encrypt(32, new_AES_key, new_AES_key_encrypted, public_keys[i].key, RSA_PKCS1_OAEP_PADDING);

pwrite(fd, new_AES_key_encrypted, new_key_size, 21);

if (new_key_size < old_key_size) {

if (ftruncate(fd, f_stat.st_size - old_key_size + new_key_size) == -1) {

return -errno;

}

}

free(old_AES_key);

free(old_AES_key_encrypted);

free(new_AES_key_encrypted);

close(fd);

return 0;

}

}

close(fd);

return -EACCES;

}

static void crypto_destroy(void * private_data){

RSA_free(private_key);

int i;

for (i = 0; i < public_keys_count; i++) {

RSA_free(public_keys[i].key);

}

free(public_keys);

}

static struct fuse_operations crypto_oper = {

.getattr = crypto_getattr,

.fgetattr = crypto_fgetattr,

.readdir = crypto_readdir,

.open = crypto_open,

.release = crypto_release,

.mknod = crypto_mknod,

.read = crypto_read,

.write = crypto_write,

.ftruncate = crypto_ftruncate,

.truncate = crypto_truncate,

.access = crypto_access,

.mkdir = crypto_mkdir,

.unlink = crypto_unlink,

.rmdir = crypto_rmdir,

.rename = crypto_rename,

.chmod = crypto_chmod,

.chown = crypto_chown,

.utimens = crypto_utimens,

.fsync = crypto_fsync,

.statfs = crypto_statfs,

.destroy = crypto_destroy

};

void load_public_key(char * key_file_name, int * pubkeys_array_size, struct stat * f_stat) {

int i;

for (i = 0; i < public_keys_count; i++) {

if (public_keys[i].owner == f_stat->st_uid) {

fprintf(stderr, "Ignore public key from file %s: public key "

"with same owner already load\n", key_file_name);

return;

}

}

int array_size = *pubkeys_array_size;

if (public_keys_count == array_size) {

array_size += 16;

void * rc = realloc(public_keys, array_size * sizeof(struct public_key));

if (rc == NULL) {

fprintf(stderr, "Can't allocate enough memory for public keys array\n");

return;

} else {

public_keys = rc;

}

}

*pubkeys_array_size = array_size;

FILE * key_file = fopen(key_file_name, "r");

if (key_file == NULL) {

fprintf(stderr, "Can't open file %s: %s\n", key_file_name,

strerror(errno));

return;

}

RSA * key = PEM_read_RSA_PUBKEY(key_file, NULL, NULL, NULL);

fclose(key_file);

if (key == NULL) {

fprintf(stderr, "Can't read public key from file %s: %s\n", key_file_name,

ERR_reason_error_string(ERR_get_error()));

return;

}

unsigned char fingerprint[20];

get_fingerprint(key, fingerprint);

for (i = 0; i < public_keys_count; i++) {

if (memcmp(fingerprint, public_keys[i].fingerprint, 20) == 0) {

fprintf(stderr, "Ignore public key from file %s: public key "

"with same fingerprint already load\n", key_file_name);

return;

}

}

public_keys[public_keys_count].key = key;

memcpy(public_keys[public_keys_count].fingerprint, fingerprint, 20);

public_keys[public_keys_count].owner = f_stat->st_uid;

public_keys[public_keys_count].owner_group = f_stat->st_gid;

public_keys_count++;

}

int main(int argc, char ** argv) {

int opt;

int pubkeys_array_size = 0;

OpenSSL_add_all_algorithms();

SSL_load_error_strings();

while ((opt = getopt(argc, argv, "k:p:l:h")) != -1) {

struct stat f_stat;

switch (opt) {

case 'k':

if (private_key != NULL) {

fprintf(stderr, "Only 1 private key need\n");

break;

}

FILE * key_file = fopen(optarg, "r");

if (key_file == NULL) {

fprintf(stderr, "Can't open file %s: %s\n", optarg,

strerror(errno));

break;

}

RSA * key = PEM_read_RSAPrivateKey(key_file, NULL, NULL, NULL);

fclose(key_file);

if (key == NULL) {

fprintf(stderr, "Can't read private key from file %s: %s\n", optarg,

ERR_reason_error_string(ERR_get_error()));

break;

}

private_key = key;

get_fingerprint(private_key, private_key_fingerprint);

break;

case 'p':

stat(optarg, &f_stat);

load_public_key(optarg, &pubkeys_array_size, &f_stat);

break;

case 'l':

stat(optarg, &f_stat);

if (!S_ISDIR(f_stat.st_mode)) {

fprintf(stderr, "Error while open library %s: "

"not a directory\n", optarg);

break;

}

struct dirent ** dir;

int n;

if ((n = scandir(optarg, &dir, NULL, NULL)) < -1) {

fprintf(stderr, "Can't open file %s: %s\n", optarg,

strerror(errno));

break;

}

int i;

for (i = 0; i < n; i++) {

stat(dir[i]->d_name, &f_stat);

if (S_ISREG(f_stat.st_mode)) {

load_public_key(dir[i]->d_name, &pubkeys_array_size, &f_stat);

}

free(dir[i]);

}

free(dir);

break;

case 'h':

default:

fprintf(stderr, "Usage: %s [options] mount_dir mount_point\n",

argv[0]);

fprintf(stderr, "Options:\n");

fprintf(stderr, " -k private_key - Path to private key file\n");

fprintf(stderr, " -p public_key - Path to public key file\n");

fprintf(stderr, " -l library - Path to dir with public keys\n");

fprintf(stderr, " -h - Show this message\n");

exit(EXIT_FAILURE);

}

}

if (optind >= argc - 1) {

fprintf(stderr, "Expected mount dir and mount point after options\n");

exit(EXIT_FAILURE);

}

if (private_key != NULL) {

printf("Private key loaded\n");

}

if (public_keys_count > 0) {

printf("%d public key%s loaded\n", public_keys_count,

public_keys_count == 1 ? "" : "s");

}

if (chdir(argv[argc - 2]) == -1) {

fprintf(stderr, "Wrong mount point: %s\n", strerror(errno));

exit(EXIT_FAILURE);

}

getcwd(mount_dir, 255);

argv[1] = argv[argc - 1];

umask(0);

return fuse_main(2, argv, &crypto_oper, NULL);

}

Лист регистрации изменений

Номера листов (страниц)

Всего

листов

(страниц)

в докум

документа

Входящий

№ сопрово

дительного

документа

и дата

Подп.

Дата

Изм

изменен

ных

заме

ненных

новых

анулиро

ванных