fishlim: Add CBC mode
This commit is contained in:
parent
7afa211849
commit
8e2559e553
103
plugins/fishlim/base64.c
Normal file
103
plugins/fishlim/base64.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Barry Steyn
|
||||
Copyright (c) 2019 <bakasura@protonmail.ch>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static const char base64_chars[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
size_t calcDecodeLength(const char *b64input) { //Calculates the length of a decoded string
|
||||
size_t len = strlen(b64input),
|
||||
padding = 0;
|
||||
|
||||
if (b64input[len - 1] == '=' && b64input[len - 2] == '=') //last two chars are =
|
||||
padding = 2;
|
||||
else if (b64input[len - 1] == '=') //last char is =
|
||||
padding = 1;
|
||||
|
||||
return (len * 3) / 4 - padding;
|
||||
}
|
||||
|
||||
int base64_encode(const unsigned char *buffer, size_t length, char **b64text) { //Encodes a binary safe base 64 string
|
||||
BIO *bio, *b64;
|
||||
BUF_MEM *bufferPtr;
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
bio = BIO_push(b64, bio);
|
||||
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
|
||||
BIO_set_close(bio, BIO_CLOSE);
|
||||
BIO_write(bio, buffer, length);
|
||||
BIO_flush(bio);
|
||||
BIO_get_mem_ptr(bio, &bufferPtr);
|
||||
|
||||
*b64text = (char *) g_malloc0((*bufferPtr).length + 1);
|
||||
memcpy(*b64text, (*bufferPtr).data, (*bufferPtr).length);
|
||||
|
||||
BIO_free_all(bio);
|
||||
|
||||
return (0); //success
|
||||
}
|
||||
|
||||
int base64_decode(const char *b64message, unsigned char **buffer, size_t *length) { //Decodes a base64 encoded string
|
||||
BIO *bio = NULL, *b64 = NULL;
|
||||
int decodeLen = 0;
|
||||
|
||||
if (strspn(b64message, base64_chars) != strlen(b64message))
|
||||
return -1;
|
||||
|
||||
decodeLen = calcDecodeLength(b64message);
|
||||
|
||||
if (decodeLen == 0)
|
||||
return -1;
|
||||
|
||||
*buffer = (unsigned char *) malloc(decodeLen + 1);
|
||||
(*buffer)[decodeLen] = '\0';
|
||||
|
||||
bio = BIO_new_mem_buf(b64message, -1);
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
bio = BIO_push(b64, bio);
|
||||
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
|
||||
*length = BIO_read(bio, *buffer, strlen(b64message));
|
||||
BIO_free_all(bio);
|
||||
|
||||
if (*length == decodeLen) {
|
||||
return 0;
|
||||
} else {
|
||||
*length = 0;
|
||||
free(*buffer);
|
||||
return -1;
|
||||
}
|
||||
}
|
36
plugins/fishlim/base64.h
Normal file
36
plugins/fishlim/base64.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Barry Steyn
|
||||
Copyright (c) 2019 <bakasura@protonmail.ch>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
int base64_encode(const unsigned char *buffer, size_t length, char **b64text);
|
||||
int base64_decode(const char *b64message, unsigned char **buffer, size_t *length);
|
||||
|
||||
#endif //BASE64_H
|
@ -32,8 +32,10 @@
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "keystore.h"
|
||||
#include "base64.h"
|
||||
#include "fish.h"
|
||||
|
||||
#define IB 64
|
||||
@ -170,21 +172,44 @@ char *fish_base64_decode(const char *message, size_t *final_len) {
|
||||
* @param [in] key Bytes of key
|
||||
* @param [in] keylen Size of key
|
||||
* @param [in] encode 1 or encrypt 0 for decrypt
|
||||
* @param [in] mode EVP_CIPH_ECB_MODE or EVP_CIPH_CBC_MODE
|
||||
* @param [out] ciphertext_len The bytes writen
|
||||
* @return Array of char with data crypted or uncrypted
|
||||
*/
|
||||
char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key, size_t keylen, int encode, size_t *ciphertext_len) {
|
||||
char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key, size_t keylen, int encode, int mode, size_t *ciphertext_len) {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
EVP_CIPHER *cipher = NULL;
|
||||
int bytes_written = 0;
|
||||
unsigned char *ciphertext = NULL;
|
||||
unsigned char *iv_ciphertext = NULL;
|
||||
unsigned char *iv = NULL;
|
||||
size_t block_size = 0;
|
||||
|
||||
if(plaintext_len == 0 || keylen == 0 || encode < 0 || encode > 1)
|
||||
if (plaintext_len == 0 || keylen == 0 || encode < 0 || encode > 1)
|
||||
return NULL;
|
||||
|
||||
/* Zero Padding */
|
||||
block_size = plaintext_len;
|
||||
|
||||
if (mode == EVP_CIPH_CBC_MODE) {
|
||||
if (encode == 1) {
|
||||
iv = (unsigned char *) g_malloc0(8);
|
||||
RAND_bytes(iv, 8);
|
||||
} else {
|
||||
if (plaintext_len <= 8) /* IV + DATA */
|
||||
return NULL;
|
||||
|
||||
iv = (unsigned char *) plaintext;
|
||||
block_size -= 8;
|
||||
plaintext += 8;
|
||||
plaintext_len -= 8;
|
||||
}
|
||||
|
||||
cipher = (EVP_CIPHER *) EVP_bf_cbc();
|
||||
} else if (mode == EVP_CIPH_ECB_MODE) {
|
||||
cipher = (EVP_CIPHER *) EVP_bf_ecb();
|
||||
}
|
||||
|
||||
/* Zero Padding */
|
||||
if (block_size % 8 != 0) {
|
||||
block_size = block_size + 8 - (block_size % 8);
|
||||
}
|
||||
@ -196,8 +221,8 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
|
||||
if (!(ctx = EVP_CIPHER_CTX_new()))
|
||||
return NULL;
|
||||
|
||||
/* Initialise the cipher operation only with mode */
|
||||
if (!EVP_CipherInit_ex(ctx, EVP_bf_ecb(), NULL, NULL, NULL, encode))
|
||||
/* Initialise the cipher operation only with mode */
|
||||
if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encode))
|
||||
return NULL;
|
||||
|
||||
/* Set custom key length */
|
||||
@ -205,7 +230,7 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
|
||||
return NULL;
|
||||
|
||||
/* Finish the initiation the cipher operation */
|
||||
if (1 != EVP_CipherInit_ex(ctx, NULL, NULL, (const unsigned char *) key, NULL, encode))
|
||||
if (1 != EVP_CipherInit_ex(ctx, NULL, NULL, (const unsigned char *) key, iv, encode))
|
||||
return NULL;
|
||||
|
||||
/* We will manage this */
|
||||
@ -226,24 +251,46 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
|
||||
/* Clean up */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return (char *) ciphertext;
|
||||
|
||||
if (mode == EVP_CIPH_CBC_MODE && encode == 1) {
|
||||
/* Join IV + DATA */
|
||||
iv_ciphertext = g_malloc0(8 + *ciphertext_len);
|
||||
|
||||
memcpy(iv_ciphertext, iv, 8);
|
||||
memcpy(&iv_ciphertext[8], ciphertext, *ciphertext_len);
|
||||
*ciphertext_len += 8;
|
||||
|
||||
g_free(ciphertext);
|
||||
g_free(iv);
|
||||
|
||||
return (char *) iv_ciphertext;
|
||||
} else {
|
||||
return (char *) ciphertext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *fish_encrypt(const char *key, size_t keylen, const char *message, size_t message_len) {
|
||||
char *fish_encrypt(const char *key, size_t keylen, const char *message, size_t message_len, int mode) {
|
||||
size_t ciphertext_len = 0;
|
||||
char *ciphertext = NULL;
|
||||
char *b64 = NULL;
|
||||
|
||||
if(keylen == 0 || message_len == 0)
|
||||
if (keylen == 0 || message_len == 0)
|
||||
return NULL;
|
||||
|
||||
ciphertext = fish_cipher(message, message_len, key, keylen, 1, &ciphertext_len);
|
||||
ciphertext = fish_cipher(message, message_len, key, keylen, 1, mode, &ciphertext_len);
|
||||
|
||||
if(ciphertext == NULL || ciphertext_len == 0)
|
||||
if (ciphertext == NULL || ciphertext_len == 0)
|
||||
return NULL;
|
||||
|
||||
b64 = fish_base64_encode((const char *) ciphertext, ciphertext_len);
|
||||
switch (mode) {
|
||||
case FISH_CBC_MODE:
|
||||
base64_encode((const unsigned char *) ciphertext, ciphertext_len, &b64);
|
||||
break;
|
||||
|
||||
case FISH_ECB_MODE:
|
||||
b64 = fish_base64_encode((const char *) ciphertext, ciphertext_len);
|
||||
}
|
||||
|
||||
g_free(ciphertext);
|
||||
|
||||
if (b64 == NULL)
|
||||
@ -252,22 +299,29 @@ char *fish_encrypt(const char *key, size_t keylen, const char *message, size_t m
|
||||
return b64;
|
||||
}
|
||||
|
||||
|
||||
char *fish_decrypt(const char *key, size_t keylen, const char *data) {
|
||||
char *fish_decrypt(const char *key, size_t keylen, const char *data, int mode) {
|
||||
size_t ciphertext_len = 0;
|
||||
char *ciphertext = NULL;
|
||||
char *plaintext = NULL;
|
||||
char *plaintext_str = NULL;
|
||||
|
||||
if(keylen == 0 || strlen(data) == 0)
|
||||
if (keylen == 0 || strlen(data) == 0)
|
||||
return NULL;
|
||||
|
||||
ciphertext = fish_base64_decode(data, &ciphertext_len);
|
||||
switch (mode) {
|
||||
case FISH_CBC_MODE:
|
||||
if (base64_decode(data, (unsigned char **) &ciphertext, &ciphertext_len) != 0)
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
case FISH_ECB_MODE:
|
||||
ciphertext = fish_base64_decode(data, &ciphertext_len);
|
||||
}
|
||||
|
||||
if (ciphertext == NULL || ciphertext_len == 0)
|
||||
return NULL;
|
||||
|
||||
plaintext = fish_cipher(ciphertext, ciphertext_len, key, keylen, 0, &ciphertext_len);
|
||||
plaintext = fish_cipher(ciphertext, ciphertext_len, key, keylen, 0, mode, &ciphertext_len);
|
||||
g_free(ciphertext);
|
||||
|
||||
if (ciphertext_len == 0)
|
||||
@ -294,7 +348,7 @@ char *fish_encrypt_for_nick(const char *nick, const char *data) {
|
||||
if (!key) return NULL;
|
||||
|
||||
/* Encrypt */
|
||||
encrypted = fish_encrypt(key, strlen(key), data, strlen(data));
|
||||
encrypted = fish_encrypt(key, strlen(key), data, strlen(data), FISH_ECB_MODE);
|
||||
|
||||
g_free(key);
|
||||
return encrypted;
|
||||
@ -312,7 +366,7 @@ char *fish_decrypt_from_nick(const char *nick, const char *data) {
|
||||
if (!key) return NULL;
|
||||
|
||||
/* Decrypt */
|
||||
decrypted = fish_decrypt(key, strlen(key), data);
|
||||
decrypted = fish_decrypt(key, strlen(key), data, FISH_ECB_MODE);
|
||||
|
||||
g_free(key);
|
||||
return decrypted;
|
||||
|
@ -30,8 +30,11 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
char *fish_encrypt(const char *key, size_t keylen, const char *message, size_t message_len);
|
||||
char *fish_decrypt(const char *key, size_t keylen, const char *data);
|
||||
# define FISH_ECB_MODE 0x1
|
||||
# define FISH_CBC_MODE 0x2
|
||||
|
||||
char *fish_encrypt(const char *key, size_t keylen, const char *message, size_t message_len, int mode);
|
||||
char *fish_decrypt(const char *key, size_t keylen, const char *data, int mode);
|
||||
char *fish_encrypt_for_nick(const char *nick, const char *data);
|
||||
char *fish_decrypt_from_nick(const char *nick, const char *data);
|
||||
|
||||
|
@ -121,7 +121,7 @@ char *keystore_get_key(const char *nick) {
|
||||
/* Key is encrypted */
|
||||
const char *encrypted = value+4;
|
||||
const char *password = get_keystore_password();
|
||||
char *decrypted = fish_decrypt(password, strlen(password), encrypted);
|
||||
char *decrypted = fish_decrypt(password, strlen(password), encrypted, FISH_ECB_MODE);
|
||||
g_free(value);
|
||||
return decrypted;
|
||||
}
|
||||
@ -204,7 +204,7 @@ gboolean keystore_store_key(const char *nick, const char *key) {
|
||||
password = get_keystore_password();
|
||||
if (password) {
|
||||
/* Encrypt the password */
|
||||
encrypted = fish_encrypt(password, strlen(password), key, strlen(key));
|
||||
encrypted = fish_encrypt(password, strlen(password), key, strlen(key), FISH_ECB_MODE);
|
||||
if (!encrypted) goto end;
|
||||
|
||||
/* Prepend "+OK " */
|
||||
|
@ -4,6 +4,7 @@ endif
|
||||
|
||||
fishlim_sources = [
|
||||
'dh1080.c',
|
||||
'base64.c',
|
||||
'fish.c',
|
||||
'irc.c',
|
||||
'keystore.c',
|
||||
|
Loading…
Reference in New Issue
Block a user