qulogic/pidgin
Clone
Summary
Browse
Changes
Graph
Merged in CMaiku/pidgin/purple-plugin-path (pull request #5)
2015-12-31, Gary Kramlich
54715f591a98
Merged in CMaiku/pidgin/purple-plugin-path (pull request #5)
Add PURPLE_PLUGIN_PATH environment variable
/*
* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*
* Written by Tomek Wasilczyk <twasilczyk@pidgin.im>
*/
#include
"internal.h"
#include
"glibcompat.h"
#include
"aescipher.h"
#include
"debug.h"
#include
"enums.h"
#include
<string.h>
#if defined(HAVE_GNUTLS)
# define PURPLE_AES_USE_GNUTLS 1
#
include
<gnutls/gnutls.h>
#
include
<gnutls/crypto.h>
#elif defined(HAVE_NSS)
# define PURPLE_AES_USE_NSS 1
#
include
<nss.h>
#
include
<pk11pub.h>
#
include
<prerror.h>
#else
# warning "No GnuTLS or NSS support"
#endif
/* 128bit */
#define PURPLE_AES_BLOCK_SIZE 16
/******************************************************************************
* Structs
*****************************************************************************/
#define PURPLE_AES_CIPHER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherPrivate))
typedef
struct
{
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
];
guchar
key
[
32
];
guint
key_size
;
gboolean
failure
;
PurpleCipherBatchMode
batch_mode
;
}
PurpleAESCipherPrivate
;
/******************************************************************************
* Enums
*****************************************************************************/
enum
{
PROP_NONE
,
PROP_BATCH_MODE
,
PROP_IV
,
PROP_KEY
,
PROP_LAST
,
};
/*******************************************************************************
* Globals
******************************************************************************/
static
GParamSpec
*
properties
[
PROP_LAST
];
/******************************************************************************
* Cipher Stuff
*****************************************************************************/
typedef
gboolean
(
*
purple_aes_cipher_crypt_func
)(
const
guchar
*
input
,
guchar
*
output
,
size_t
len
,
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
,
PurpleCipherBatchMode
batch_mode
);
static
void
purple_aes_cipher_reset
(
PurpleCipher
*
cipher
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
g_return_if_fail
(
priv
!=
NULL
);
memset
(
priv
->
iv
,
0
,
sizeof
(
priv
->
iv
));
memset
(
priv
->
key
,
0
,
sizeof
(
priv
->
key
));
priv
->
key_size
=
32
;
/* 256bit */
priv
->
failure
=
FALSE
;
}
static
void
purple_aes_cipher_set_iv
(
PurpleCipher
*
cipher
,
guchar
*
iv
,
size_t
len
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
if
((
len
>
0
&&
iv
==
NULL
)
||
(
len
!=
0
&&
len
!=
sizeof
(
priv
->
iv
)))
{
purple_debug_error
(
"cipher-aes"
,
"invalid IV length
\n
"
);
priv
->
failure
=
TRUE
;
return
;
}
if
(
len
==
0
)
memset
(
priv
->
iv
,
0
,
sizeof
(
priv
->
iv
));
else
memcpy
(
priv
->
iv
,
iv
,
len
);
g_object_notify_by_pspec
(
G_OBJECT
(
cipher
),
properties
[
PROP_IV
]);
}
static
void
purple_aes_cipher_set_key
(
PurpleCipher
*
cipher
,
const
guchar
*
key
,
size_t
len
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
if
((
len
>
0
&&
key
==
NULL
)
||
(
len
!=
0
&&
len
!=
16
&&
len
!=
24
&&
len
!=
32
))
{
purple_debug_error
(
"cipher-aes"
,
"invalid key length
\n
"
);
priv
->
failure
=
TRUE
;
return
;
}
priv
->
key_size
=
len
;
memset
(
priv
->
key
,
0
,
sizeof
(
priv
->
key
));
if
(
len
>
0
)
memcpy
(
priv
->
key
,
key
,
len
);
g_object_notify_by_pspec
(
G_OBJECT
(
cipher
),
properties
[
PROP_KEY
]);
}
static
guchar
*
purple_aes_cipher_pad_pkcs7
(
const
guchar
input
[],
size_t
in_len
,
size_t
*
out_len
)
{
int
padding_len
,
total_len
;
guchar
*
padded
;
g_return_val_if_fail
(
input
!=
NULL
,
NULL
);
g_return_val_if_fail
(
out_len
!=
NULL
,
NULL
);
padding_len
=
PURPLE_AES_BLOCK_SIZE
-
(
in_len
%
PURPLE_AES_BLOCK_SIZE
);
total_len
=
in_len
+
padding_len
;
g_assert
((
total_len
%
PURPLE_AES_BLOCK_SIZE
)
==
0
);
padded
=
g_new
(
guchar
,
total_len
);
*
out_len
=
total_len
;
memcpy
(
padded
,
input
,
in_len
);
memset
(
padded
+
in_len
,
padding_len
,
padding_len
);
return
padded
;
}
static
ssize_t
purple_aes_cipher_unpad_pkcs7
(
guchar
input
[],
size_t
in_len
)
{
guchar
padding_len
,
i
;
size_t
out_len
;
g_return_val_if_fail
(
input
!=
NULL
,
-1
);
g_return_val_if_fail
(
in_len
>
0
,
-1
);
padding_len
=
input
[
in_len
-
1
];
if
(
padding_len
==
0
||
padding_len
>
PURPLE_AES_BLOCK_SIZE
||
padding_len
>
in_len
)
{
purple_debug_warning
(
"cipher-aes"
,
"Invalid padding length: %d (total %"
G_GSIZE_FORMAT
") - "
"most probably, the key was invalid
\n
"
,
padding_len
,
in_len
);
return
-1
;
}
out_len
=
in_len
-
padding_len
;
for
(
i
=
0
;
i
<
padding_len
;
i
++
)
{
if
(
input
[
out_len
+
i
]
!=
padding_len
)
{
purple_debug_warning
(
"cipher-aes"
,
"Padding doesn't match at pos %d (found %02x, "
"expected %02x) - "
"most probably, the key was invalid
\n
"
,
i
,
input
[
out_len
+
i
],
padding_len
);
return
-1
;
}
}
memset
(
input
+
out_len
,
0
,
padding_len
);
return
out_len
;
}
#ifdef PURPLE_AES_USE_GNUTLS
static
gnutls_cipher_hd_t
purple_aes_cipher_gnutls_crypt_init
(
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
)
{
gnutls_cipher_hd_t
handle
;
gnutls_cipher_algorithm_t
algorithm
;
gnutls_datum_t
key_info
,
iv_info
;
int
ret
;
if
(
key_size
==
16
)
algorithm
=
GNUTLS_CIPHER_AES_128_CBC
;
else
if
(
key_size
==
24
)
algorithm
=
GNUTLS_CIPHER_AES_192_CBC
;
else
if
(
key_size
==
32
)
algorithm
=
GNUTLS_CIPHER_AES_256_CBC
;
else
g_return_val_if_reached
(
NULL
);
key_info
.
data
=
key
;
key_info
.
size
=
key_size
;
iv_info
.
data
=
iv
;
iv_info
.
size
=
PURPLE_AES_BLOCK_SIZE
;
ret
=
gnutls_cipher_init
(
&
handle
,
algorithm
,
&
key_info
,
&
iv_info
);
if
(
ret
!=
0
)
{
purple_debug_error
(
"cipher-aes"
,
"gnutls_cipher_init failed: %d
\n
"
,
ret
);
return
NULL
;
}
return
handle
;
}
static
gboolean
purple_aes_cipher_gnutls_encrypt
(
const
guchar
*
input
,
guchar
*
output
,
size_t
len
,
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
,
PurpleCipherBatchMode
batch_mode
)
{
gnutls_cipher_hd_t
handle
;
int
ret
;
/* We have to simulate ECB mode, which is not supported by GnuTLS. */
if
(
batch_mode
==
PURPLE_CIPHER_BATCH_MODE_ECB
)
{
size_t
i
;
for
(
i
=
0
;
i
<
len
/
PURPLE_AES_BLOCK_SIZE
;
i
++
)
{
int
offset
=
i
*
PURPLE_AES_BLOCK_SIZE
;
guchar
iv_local
[
PURPLE_AES_BLOCK_SIZE
];
gboolean
succ
;
memcpy
(
iv_local
,
iv
,
sizeof
(
iv_local
));
succ
=
purple_aes_cipher_gnutls_encrypt
(
input
+
offset
,
output
+
offset
,
PURPLE_AES_BLOCK_SIZE
,
iv_local
,
key
,
key_size
,
PURPLE_CIPHER_BATCH_MODE_CBC
);
if
(
!
succ
)
return
FALSE
;
}
return
TRUE
;
}
handle
=
purple_aes_cipher_gnutls_crypt_init
(
iv
,
key
,
key_size
);
if
(
handle
==
NULL
)
return
FALSE
;
ret
=
gnutls_cipher_encrypt2
(
handle
,
(
guchar
*
)
input
,
len
,
output
,
len
);
gnutls_cipher_deinit
(
handle
);
if
(
ret
!=
0
)
{
purple_debug_error
(
"cipher-aes"
,
"gnutls_cipher_encrypt2 failed: %d
\n
"
,
ret
);
return
FALSE
;
}
return
TRUE
;
}
static
gboolean
purple_aes_cipher_gnutls_decrypt
(
const
guchar
*
input
,
guchar
*
output
,
size_t
len
,
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
,
PurpleCipherBatchMode
batch_mode
)
{
gnutls_cipher_hd_t
handle
;
int
ret
;
/* We have to simulate ECB mode, which is not supported by GnuTLS. */
if
(
batch_mode
==
PURPLE_CIPHER_BATCH_MODE_ECB
)
{
size_t
i
;
for
(
i
=
0
;
i
<
len
/
PURPLE_AES_BLOCK_SIZE
;
i
++
)
{
int
offset
=
i
*
PURPLE_AES_BLOCK_SIZE
;
guchar
iv_local
[
PURPLE_AES_BLOCK_SIZE
];
gboolean
succ
;
memcpy
(
iv_local
,
iv
,
sizeof
(
iv_local
));
succ
=
purple_aes_cipher_gnutls_decrypt
(
input
+
offset
,
output
+
offset
,
PURPLE_AES_BLOCK_SIZE
,
iv_local
,
key
,
key_size
,
PURPLE_CIPHER_BATCH_MODE_CBC
);
if
(
!
succ
)
return
FALSE
;
}
return
TRUE
;
}
handle
=
purple_aes_cipher_gnutls_crypt_init
(
iv
,
key
,
key_size
);
if
(
handle
==
NULL
)
return
FALSE
;
ret
=
gnutls_cipher_decrypt2
(
handle
,
input
,
len
,
output
,
len
);
gnutls_cipher_deinit
(
handle
);
if
(
ret
!=
0
)
{
purple_debug_error
(
"cipher-aes"
,
"gnutls_cipher_decrypt2 failed: %d
\n
"
,
ret
);
return
FALSE
;
}
return
TRUE
;
}
#elif defined(PURPLE_AES_USE_NSS)
typedef
struct
{
PK11SlotInfo
*
slot
;
PK11SymKey
*
sym_key
;
SECItem
*
sec_param
;
PK11Context
*
enc_context
;
}
PurpleAESCipherNSSContext
;
static
void
purple_aes_cipher_nss_cleanup
(
PurpleAESCipherNSSContext
*
context
)
{
g_return_if_fail
(
context
!=
NULL
);
if
(
context
->
enc_context
!=
NULL
)
PK11_DestroyContext
(
context
->
enc_context
,
TRUE
);
if
(
context
->
sec_param
!=
NULL
)
SECITEM_FreeItem
(
context
->
sec_param
,
TRUE
);
if
(
context
->
sym_key
!=
NULL
)
PK11_FreeSymKey
(
context
->
sym_key
);
if
(
context
->
slot
!=
NULL
)
PK11_FreeSlot
(
context
->
slot
);
memset
(
context
,
0
,
sizeof
(
PurpleAESCipherNSSContext
));
}
static
gboolean
purple_aes_cipher_nss_crypt
(
const
guchar
*
input
,
guchar
*
output
,
size_t
len
,
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
,
CK_ATTRIBUTE_TYPE
operation
,
CK_MECHANISM_TYPE
cipher_mech
)
{
PurpleAESCipherNSSContext
context
;
SECItem
key_item
,
iv_item
;
SECStatus
ret
;
int
outlen
=
0
;
unsigned
int
outlen_tmp
=
0
;
memset
(
&
context
,
0
,
sizeof
(
PurpleAESCipherNSSContext
));
if
(
NSS_NoDB_Init
(
NULL
)
!=
SECSuccess
)
{
purple_debug_error
(
"cipher-aes"
,
"NSS_NoDB_Init failed: %d
\n
"
,
PR_GetError
());
return
FALSE
;
}
context
.
slot
=
PK11_GetBestSlot
(
cipher_mech
,
NULL
);
if
(
context
.
slot
==
NULL
)
{
purple_debug_error
(
"cipher-aes"
,
"PK11_GetBestSlot failed: %d
\n
"
,
PR_GetError
());
return
FALSE
;
}
key_item
.
type
=
siBuffer
;
key_item
.
data
=
key
;
key_item
.
len
=
key_size
;
context
.
sym_key
=
PK11_ImportSymKey
(
context
.
slot
,
cipher_mech
,
PK11_OriginUnwrap
,
CKA_ENCRYPT
,
&
key_item
,
NULL
);
if
(
context
.
sym_key
==
NULL
)
{
purple_debug_error
(
"cipher-aes"
,
"PK11_ImportSymKey failed: %d
\n
"
,
PR_GetError
());
purple_aes_cipher_nss_cleanup
(
&
context
);
return
FALSE
;
}
iv_item
.
type
=
siBuffer
;
iv_item
.
data
=
iv
;
iv_item
.
len
=
PURPLE_AES_BLOCK_SIZE
;
context
.
sec_param
=
PK11_ParamFromIV
(
cipher_mech
,
&
iv_item
);
if
(
context
.
sec_param
==
NULL
)
{
purple_debug_error
(
"cipher-aes"
,
"PK11_ParamFromIV failed: %d
\n
"
,
PR_GetError
());
purple_aes_cipher_nss_cleanup
(
&
context
);
return
FALSE
;
}
context
.
enc_context
=
PK11_CreateContextBySymKey
(
cipher_mech
,
operation
,
context
.
sym_key
,
context
.
sec_param
);
if
(
context
.
enc_context
==
NULL
)
{
purple_debug_error
(
"cipher-aes"
,
"PK11_CreateContextBySymKey failed: %d
\n
"
,
PR_GetError
());
purple_aes_cipher_nss_cleanup
(
&
context
);
return
FALSE
;
}
ret
=
PK11_CipherOp
(
context
.
enc_context
,
output
,
&
outlen
,
len
,
(
guchar
*
)
input
,
len
);
if
(
ret
!=
SECSuccess
)
{
purple_debug_error
(
"cipher-aes"
,
"PK11_CipherOp failed: %d
\n
"
,
PR_GetError
());
purple_aes_cipher_nss_cleanup
(
&
context
);
return
FALSE
;
}
ret
=
PK11_DigestFinal
(
context
.
enc_context
,
output
+
outlen
,
&
outlen_tmp
,
len
-
outlen
);
if
(
ret
!=
SECSuccess
)
{
purple_debug_error
(
"cipher-aes"
,
"PK11_DigestFinal failed: %d
\n
"
,
PR_GetError
());
purple_aes_cipher_nss_cleanup
(
&
context
);
return
FALSE
;
}
purple_aes_cipher_nss_cleanup
(
&
context
);
outlen
+=
outlen_tmp
;
if
(
outlen
!=
(
int
)
len
)
{
purple_debug_error
(
"cipher-aes"
,
"resulting length doesn't match: %d (expected: %"
G_GSIZE_FORMAT
")
\n
"
,
outlen
,
len
);
return
FALSE
;
}
return
TRUE
;
}
static
CK_MECHANISM_TYPE
purple_aes_cipher_nss_batch_mode
(
PurpleCipherBatchMode
batch_mode
)
{
switch
(
batch_mode
)
{
case
PURPLE_CIPHER_BATCH_MODE_CBC
:
return
CKM_AES_CBC
;
case
PURPLE_CIPHER_BATCH_MODE_ECB
:
return
CKM_AES_ECB
;
}
return
CKM_AES_CBC
;
}
static
gboolean
purple_aes_cipher_nss_encrypt
(
const
guchar
*
input
,
guchar
*
output
,
size_t
len
,
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
,
PurpleCipherBatchMode
batch_mode
)
{
return
purple_aes_cipher_nss_crypt
(
input
,
output
,
len
,
iv
,
key
,
key_size
,
CKA_ENCRYPT
,
purple_aes_cipher_nss_batch_mode
(
batch_mode
));
}
static
gboolean
purple_aes_cipher_nss_decrypt
(
const
guchar
*
input
,
guchar
*
output
,
size_t
len
,
guchar
iv
[
PURPLE_AES_BLOCK_SIZE
],
guchar
key
[
32
],
guint
key_size
,
PurpleCipherBatchMode
batch_mode
)
{
return
purple_aes_cipher_nss_crypt
(
input
,
output
,
len
,
iv
,
key
,
key_size
,
CKA_DECRYPT
,
purple_aes_cipher_nss_batch_mode
(
batch_mode
));
}
#endif
/* PURPLE_AES_USE_NSS */
static
ssize_t
purple_aes_cipher_encrypt
(
PurpleCipher
*
cipher
,
const
guchar
input
[],
size_t
in_len
,
guchar
output
[],
size_t
out_size
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
purple_aes_cipher_crypt_func
encrypt_func
;
guchar
*
input_padded
;
size_t
out_len
=
0
;
gboolean
succ
;
if
(
priv
->
failure
)
return
-1
;
input_padded
=
purple_aes_cipher_pad_pkcs7
(
input
,
in_len
,
&
out_len
);
if
(
out_len
>
out_size
)
{
purple_debug_error
(
"cipher-aes"
,
"Output buffer too small (%"
G_GSIZE_FORMAT
" > %"
G_GSIZE_FORMAT
")"
,
out_len
,
out_size
);
memset
(
input_padded
,
0
,
out_len
);
g_free
(
input_padded
);
return
-1
;
}
#if defined(PURPLE_AES_USE_GNUTLS)
encrypt_func
=
purple_aes_cipher_gnutls_encrypt
;
#elif defined(PURPLE_AES_USE_NSS)
encrypt_func
=
purple_aes_cipher_nss_encrypt
;
#else
purple_debug_error
(
"cipher-aes"
,
"No matching encrypt_func
\n
"
);
return
-1
;
#endif
succ
=
encrypt_func
(
input_padded
,
output
,
out_len
,
priv
->
iv
,
priv
->
key
,
priv
->
key_size
,
priv
->
batch_mode
);
memset
(
input_padded
,
0
,
out_len
);
g_free
(
input_padded
);
if
(
!
succ
)
{
memset
(
output
,
0
,
out_len
);
return
-1
;
}
return
out_len
;
}
static
ssize_t
purple_aes_cipher_decrypt
(
PurpleCipher
*
cipher
,
const
guchar
input
[],
size_t
in_len
,
guchar
output
[],
size_t
out_size
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
purple_aes_cipher_crypt_func
decrypt_func
;
gboolean
succ
;
ssize_t
out_len
;
if
(
priv
->
failure
)
return
-1
;
if
(
in_len
>
out_size
)
{
purple_debug_error
(
"cipher-aes"
,
"Output buffer too small
\n
"
);
return
-1
;
}
if
((
in_len
%
PURPLE_AES_BLOCK_SIZE
)
!=
0
||
in_len
==
0
)
{
purple_debug_error
(
"cipher-aes"
,
"Malformed data
\n
"
);
return
-1
;
}
#if defined(PURPLE_AES_USE_GNUTLS)
decrypt_func
=
purple_aes_cipher_gnutls_decrypt
;
#elif defined(PURPLE_AES_USE_NSS)
decrypt_func
=
purple_aes_cipher_nss_decrypt
;
#else
purple_debug_error
(
"cipher-aes"
,
"No matching decrypt_func
\n
"
);
return
-1
;
#endif
succ
=
decrypt_func
(
input
,
output
,
in_len
,
priv
->
iv
,
priv
->
key
,
priv
->
key_size
,
priv
->
batch_mode
);
if
(
!
succ
)
{
memset
(
output
,
0
,
in_len
);
return
-1
;
}
out_len
=
purple_aes_cipher_unpad_pkcs7
(
output
,
in_len
);
if
(
out_len
<
0
)
{
memset
(
output
,
0
,
in_len
);
return
-1
;
}
return
out_len
;
}
static
size_t
purple_aes_cipher_get_key_size
(
PurpleCipher
*
cipher
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
return
priv
->
key_size
;
}
static
void
purple_aes_cipher_set_batch_mode
(
PurpleCipher
*
cipher
,
PurpleCipherBatchMode
mode
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
if
(
mode
!=
PURPLE_CIPHER_BATCH_MODE_CBC
&&
mode
!=
PURPLE_CIPHER_BATCH_MODE_ECB
)
{
purple_debug_error
(
"cipher-aes"
,
"unsupported batch mode
\n
"
);
priv
->
failure
=
TRUE
;
}
priv
->
batch_mode
=
mode
;
g_object_notify_by_pspec
(
G_OBJECT
(
cipher
),
properties
[
PROP_BATCH_MODE
]);
}
static
PurpleCipherBatchMode
purple_aes_cipher_get_batch_mode
(
PurpleCipher
*
cipher
)
{
PurpleAESCipherPrivate
*
priv
=
PURPLE_AES_CIPHER_GET_PRIVATE
(
cipher
);
return
priv
->
batch_mode
;
}
static
size_t
purple_aes_cipher_get_block_size
(
PurpleCipher
*
cipher
)
{
return
PURPLE_AES_BLOCK_SIZE
;
}
/******************************************************************************
* Object Stuff
*****************************************************************************/
static
void
purple_aes_cipher_get_property
(
GObject
*
obj
,
guint
param_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
PurpleCipher
*
cipher
=
PURPLE_CIPHER
(
obj
);
switch
(
param_id
)
{
case
PROP_BATCH_MODE
:
g_value_set_enum
(
value
,
purple_cipher_get_batch_mode
(
cipher
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
purple_aes_cipher_set_property
(
GObject
*
obj
,
guint
param_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
PurpleCipher
*
cipher
=
PURPLE_CIPHER
(
obj
);
switch
(
param_id
)
{
case
PROP_BATCH_MODE
:
purple_cipher_set_batch_mode
(
cipher
,
g_value_get_enum
(
value
));
break
;
case
PROP_IV
:
{
guchar
*
iv
=
(
guchar
*
)
g_value_get_string
(
value
);
purple_cipher_set_iv
(
cipher
,
iv
,
strlen
((
gchar
*
)
iv
));
}
break
;
case
PROP_KEY
:
purple_cipher_set_key
(
cipher
,
(
guchar
*
)
g_value_get_string
(
value
),
purple_aes_cipher_get_key_size
(
cipher
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
purple_aes_cipher_class_init
(
PurpleAESCipherClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
PurpleCipherClass
*
cipher_class
=
PURPLE_CIPHER_CLASS
(
klass
);
obj_class
->
get_property
=
purple_aes_cipher_get_property
;
obj_class
->
set_property
=
purple_aes_cipher_set_property
;
cipher_class
->
reset
=
purple_aes_cipher_reset
;
cipher_class
->
set_iv
=
purple_aes_cipher_set_iv
;
cipher_class
->
encrypt
=
purple_aes_cipher_encrypt
;
cipher_class
->
decrypt
=
purple_aes_cipher_decrypt
;
cipher_class
->
set_key
=
purple_aes_cipher_set_key
;
cipher_class
->
get_key_size
=
purple_aes_cipher_get_key_size
;
cipher_class
->
set_batch_mode
=
purple_aes_cipher_set_batch_mode
;
cipher_class
->
get_batch_mode
=
purple_aes_cipher_get_batch_mode
;
cipher_class
->
get_block_size
=
purple_aes_cipher_get_block_size
;
g_type_class_add_private
(
klass
,
sizeof
(
PurpleAESCipherPrivate
));
properties
[
PROP_BATCH_MODE
]
=
g_param_spec_enum
(
"batch-mode"
,
"batch-mode"
,
"batch-mode"
,
PURPLE_TYPE_CIPHER_BATCH_MODE
,
PURPLE_CIPHER_BATCH_MODE_CBC
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_IV
]
=
g_param_spec_string
(
"iv"
,
"iv"
,
"iv"
,
NULL
,
G_PARAM_WRITABLE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_KEY
]
=
g_param_spec_string
(
"key"
,
"key"
,
"key"
,
NULL
,
G_PARAM_WRITABLE
|
G_PARAM_STATIC_STRINGS
);
g_object_class_install_properties
(
obj_class
,
PROP_LAST
,
properties
);
}
static
void
purple_aes_cipher_init
(
PurpleCipher
*
cipher
)
{
purple_cipher_reset
(
cipher
);
}
/******************************************************************************
* API
*****************************************************************************/
GType
purple_aes_cipher_get_type
(
void
)
{
static
GType
type
=
0
;
if
(
type
==
0
)
{
static
const
GTypeInfo
info
=
{
sizeof
(
PurpleAESCipherClass
),
NULL
,
NULL
,
(
GClassInitFunc
)
purple_aes_cipher_class_init
,
NULL
,
NULL
,
sizeof
(
PurpleAESCipher
),
0
,
(
GInstanceInitFunc
)
purple_aes_cipher_init
,
NULL
};
type
=
g_type_register_static
(
PURPLE_TYPE_CIPHER
,
"PurpleAESCipher"
,
&
info
,
0
);
}
return
type
;
}
PurpleCipher
*
purple_aes_cipher_new
(
void
)
{
return
g_object_new
(
PURPLE_TYPE_AES_CIPHER
,
NULL
);
}