/** * mega_aes_key_get_ubase64: * @aes_key: a #MegaAesKey * * Get UBase64 encoded key data. * * Returns: UBase64 encoded string. */ gchar* mega_aes_key_get_ubase64(MegaAesKey* aes_key) { g_return_val_if_fail(MEGA_IS_AES_KEY(aes_key), NULL); g_return_val_if_fail(aes_key->priv->loaded, NULL); return mega_base64urlencode(aes_key->priv->key, 16); }
/** * mega_aes_key_make_username_hash: * @aes_key: a #MegaAesKey * @username: E-mail * * Generate username hash (uh paraemter for 'us' API call) used for authentication to mega.nz. * * Returns: Username hash string */ gchar* mega_aes_key_make_username_hash(MegaAesKey* aes_key, const gchar* username) { gchar* username_lower; g_return_val_if_fail(MEGA_IS_AES_KEY(aes_key), NULL); g_return_val_if_fail(username != NULL, NULL); username_lower = g_ascii_strdown(username, -1); gint l, i; guchar hash[16] = {0}, hash_tmp[16], oh[8]; for (i = 0, l = strlen(username_lower); i < l; i++) hash[i % 16] ^= username_lower[i]; for (i = 16384; i--; ) { AES_encrypt(hash, hash_tmp, &aes_key->priv->enc_key); memcpy(hash, hash_tmp, 16); } memcpy(oh, hash, 4); memcpy(oh + 4, hash + 8, 4); g_free(username_lower); return mega_base64urlencode(oh, 8); }
void test_rsa(void) { // my keys MegaAesKey* mk = mega_aes_key_new_from_ubase64(MY_MASTER_KEY); MegaRsaKey* rk = mega_rsa_key_new(); g_assert(mega_rsa_key_load_enc_privk(rk, MY_PRIVK_ENC, mk)); g_assert(mega_rsa_key_load_pubk(rk, MY_PUBK)); GBytes* sid_bytes = mega_rsa_key_decrypt(rk, MY_CSID); g_assert_cmpuint(g_bytes_get_size(sid_bytes), >=, 43); gchar* sid = mega_base64urlencode(g_bytes_get_data(sid_bytes, NULL), 43); g_assert_cmpstr(sid, ==, MY_SID); g_assert_cmpstr(mega_rsa_key_get_pubk(rk), ==, MY_PUBK); // last block can be different, because it's random padded g_assert_cmpstr(trim_last_block(mega_rsa_key_get_enc_privk(rk, mk)), ==, trim_last_block(MY_PRIVK_ENC)); // test encryption guchar plain[16] = {0xff}; gchar* cipher = mega_rsa_key_encrypt(rk, plain, 16); GBytes* plain_bytes = mega_rsa_key_decrypt(rk, cipher); g_assert(plain_bytes != NULL); g_assert_cmpuint(g_bytes_get_size(plain_bytes), >, 16); g_assert(memcmp(g_bytes_get_data(plain_bytes, NULL), plain, 16) == 0); // Mega BUG: Plaintext can't start with zero! memset(plain, 0, 16); cipher = mega_rsa_key_encrypt(rk, plain, 16); plain_bytes = mega_rsa_key_decrypt(rk, cipher); g_assert(plain_bytes != NULL); g_assert_cmpuint(g_bytes_get_size(plain_bytes), >, 16); g_assert(memcmp(g_bytes_get_data(plain_bytes, NULL), plain, 16) == 0); // generate key g_assert(mega_rsa_key_generate(rk)); gchar* privk1 = mega_rsa_key_get_enc_privk(rk, mk); gchar* pubk1 = mega_rsa_key_get_pubk(rk); g_assert(mega_rsa_key_generate(rk)); gchar* privk2 = mega_rsa_key_get_enc_privk(rk, mk); gchar* pubk2 = mega_rsa_key_get_pubk(rk); g_assert_cmpstr(pubk1, !=, pubk2); // last block can be different, because it's random padded g_assert_cmpstr(trim_last_block(privk1), !=, trim_last_block(privk2)); // INVALID USES g_assert(!mega_rsa_key_load_enc_privk(rk, MY_CSID, mk)); g_assert(!mega_rsa_key_load_pubk(rk, MY_CSID)); g_assert(!mega_rsa_key_load_enc_privk(rk, KEY_INVALID, mk)); g_assert(!mega_rsa_key_load_pubk(rk, KEY_INVALID)); g_assert(!mega_rsa_key_load_enc_privk(rk, KEY_NULL, mk)); g_assert(!mega_rsa_key_load_pubk(rk, KEY_NULL)); }
/** * mega_aes_key_encrypt: * @aes_key: a #MegaAesKey * @plain: (in) (element-type guint8) (array length=len): Plaintext input data * @len: (in): 16 byte aligned length of plaintext data. * * Encrypt binary data into ubase64 encoded string. * * Returns: UBase64 encoded ciphertext. */ gchar* mega_aes_key_encrypt(MegaAesKey* aes_key, const guchar* plain, gsize len) { guchar* cipher; gchar* str; g_return_val_if_fail(MEGA_IS_AES_KEY(aes_key), NULL); g_return_val_if_fail(plain != NULL, NULL); g_return_val_if_fail((len % 16) == 0, NULL); g_return_val_if_fail(len > 0, NULL); cipher = g_malloc0(len); mega_aes_key_encrypt_raw(aes_key, plain, cipher, len); str = mega_base64urlencode(cipher, len); g_free(cipher); return str; }
/** * mega_aes_key_encrypt_cbc: * @aes_key: a #MegaAesKey * @plain: (in) (element-type guint8) (array length=len): Plaintext input data * @len: (in): 16 byte aligned length of plaintext data. * * Encrypt plaintext blocks using AES key in CBC mode with zero IV into UBase64 * ciphertext. * * Returns: UBase64 encoded ciphertext. */ gchar* mega_aes_key_encrypt_cbc(MegaAesKey* aes_key, const guchar* plain, gsize len) { guchar* cipher; gchar* str; guchar iv[AES_BLOCK_SIZE] = {0}; g_return_val_if_fail(MEGA_IS_AES_KEY(aes_key), NULL); g_return_val_if_fail(plain != NULL, NULL); g_return_val_if_fail((len % 16) == 0, NULL); g_return_val_if_fail(len > 0, NULL); cipher = g_malloc0(len); AES_cbc_encrypt(plain, cipher, len, &aes_key->priv->enc_key, iv, 1); str = mega_base64urlencode(cipher, len); g_free(cipher); return str; }