fishlim: Add CBC mode

This commit is contained in:
BakasuraRCE 2019-05-25 16:50:57 -05:00
parent 7afa211849
commit 8e2559e553
6 changed files with 221 additions and 24 deletions

103
plugins/fishlim/base64.c Normal file
View 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
View 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

View File

@ -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;

View File

@ -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);

View File

@ -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 " */

View File

@ -4,6 +4,7 @@ endif
fishlim_sources = [
'dh1080.c',
'base64.c',
'fish.c',
'irc.c',
'keystore.c',