comparison libpurple/cipher.c @ 21908:f786e478e08b

HMAC digest support from Elliott Sales de Andrade committer: Gary Kramlich <grim@reaperworld.com>
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Thu, 20 Dec 2007 03:44:01 +0000
parents 03463c52b9d7
children 76e0463db3aa
comparison
equal deleted inserted replaced
21907:03463c52b9d7 21908:f786e478e08b
62 #include "value.h" 62 #include "value.h"
63 63
64 /******************************************************************************* 64 /*******************************************************************************
65 * MD5 65 * MD5
66 ******************************************************************************/ 66 ******************************************************************************/
67 #define MD5_HMAC_BLOCK_SIZE 64
68
67 struct MD5Context { 69 struct MD5Context {
68 guint32 total[2]; 70 guint32 total[2];
69 guint32 state[4]; 71 guint32 state[4];
70 guchar buffer[64]; 72 guchar buffer[64];
71 }; 73 };
323 *out_len = 16; 325 *out_len = 16;
324 326
325 return TRUE; 327 return TRUE;
326 } 328 }
327 329
330 static size_t
331 md5_get_block_size(PurpleCipherContext *context)
332 {
333 /* This does not change (in this case) */
334 return MD5_HMAC_BLOCK_SIZE;
335 }
336
328 static PurpleCipherOps MD5Ops = { 337 static PurpleCipherOps MD5Ops = {
329 NULL, /* Set option */ 338 NULL, /* Set option */
330 NULL, /* Get option */ 339 NULL, /* Get option */
331 md5_init, /* init */ 340 md5_init, /* init */
332 md5_reset, /* reset */ 341 md5_reset, /* reset */
340 NULL, /* get salt size */ 349 NULL, /* get salt size */
341 NULL, /* set key */ 350 NULL, /* set key */
342 NULL, /* get key size */ 351 NULL, /* get key size */
343 NULL, /* set batch mode */ 352 NULL, /* set batch mode */
344 NULL, /* get batch mode */ 353 NULL, /* get batch mode */
345 354 md5_get_block_size, /* get block size */
346 /* padding */ 355 NULL /* set key with len */
347 NULL,
348 NULL
349 }; 356 };
350 357
351 /******************************************************************************* 358 /*******************************************************************************
352 * MD4 359 * MD4
353 ******************************************************************************/ 360 ******************************************************************************/
576 md4_context = purple_cipher_context_get_data(context); 583 md4_context = purple_cipher_context_get_data(context);
577 memset(md4_context, 0, sizeof(md4_context)); 584 memset(md4_context, 0, sizeof(md4_context));
578 585
579 g_free(md4_context); 586 g_free(md4_context);
580 md4_context = NULL; 587 md4_context = NULL;
588 }
589
590 static size_t
591 md4_get_block_size(PurpleCipherContext *context)
592 {
593 /* This does not change (in this case) */
594 return MD4_HMAC_BLOCK_SIZE;
581 } 595 }
582 596
583 static PurpleCipherOps MD4Ops = { 597 static PurpleCipherOps MD4Ops = {
584 NULL, /* Set option */ 598 NULL, /* Set option */
585 NULL, /* Get option */ 599 NULL, /* Get option */
595 NULL, /* get salt size */ 609 NULL, /* get salt size */
596 NULL, /* set key */ 610 NULL, /* set key */
597 NULL, /* get key size */ 611 NULL, /* get key size */
598 NULL, /* set batch mode */ 612 NULL, /* set batch mode */
599 NULL, /* get batch mode */ 613 NULL, /* get batch mode */
600 614 md4_get_block_size, /* get block size */
601 /* padding */ 615 NULL /* set key with len */
602 NULL, 616 };
603 NULL 617
618 /*******************************************************************************
619 * HMAC
620 ******************************************************************************/
621
622 struct HMAC_Context {
623 PurpleCipherContext *hash;
624 char *name;
625 int blocksize;
626 guchar *opad;
627 };
628
629 static void
630 hmac_init(PurpleCipherContext *context, gpointer extra)
631 {
632 struct HMAC_Context *hctx;
633 hctx = g_new0(struct HMAC_Context, 1);
634 purple_cipher_context_set_data(context, hctx);
635 purple_cipher_context_reset(context, extra);
636 }
637
638 static void
639 hmac_reset(PurpleCipherContext *context, gpointer extra)
640 {
641 struct HMAC_Context *hctx;
642
643 hctx = purple_cipher_context_get_data(context);
644
645 g_free(hctx->name);
646 hctx->name = NULL;
647 if (hctx->hash)
648 purple_cipher_context_destroy(hctx->hash);
649 hctx->hash = NULL;
650 hctx->blocksize = 0;
651 g_free(hctx->opad);
652 hctx->opad = NULL;
653 }
654
655 static void
656 hmac_set_opt(PurpleCipherContext *context, const gchar *name, void *value)
657 {
658 struct HMAC_Context *hctx;
659
660 hctx = purple_cipher_context_get_data(context);
661
662 if (!strcmp(name, "hash")) {
663 g_free(hctx->name);
664 if (hctx->hash)
665 purple_cipher_context_destroy(hctx->hash);
666 hctx->name = g_strdup((char*)value);
667 hctx->hash = purple_cipher_context_new_by_name((char *)value, NULL);
668 hctx->blocksize = purple_cipher_context_get_block_size(hctx->hash);
669 }
670 }
671
672 static void *
673 hmac_get_opt(PurpleCipherContext *context, const gchar *name)
674 {
675 struct HMAC_Context *hctx;
676
677 hctx = purple_cipher_context_get_data(context);
678
679 if (!strcmp(name, "hash")) {
680 return hctx->name;
681 }
682
683 return NULL;
684 }
685
686 static void
687 hmac_append(PurpleCipherContext *context, const guchar *data, size_t len)
688 {
689 struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
690
691 g_return_if_fail(hctx->hash != NULL);
692
693 purple_cipher_context_append(hctx->hash, data, len);
694 }
695
696 static gboolean
697 hmac_digest(PurpleCipherContext *context, size_t in_len, guchar *out, size_t *out_len)
698 {
699 struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
700 PurpleCipherContext *hash = hctx->hash;
701 guchar *inner_hash;
702 size_t hash_len;
703 gboolean result;
704
705 g_return_val_if_fail(hash != NULL, FALSE);
706
707 inner_hash = g_malloc(100); /* TODO: Should be enough for now... */
708 result = purple_cipher_context_digest(hash, 100, inner_hash, &hash_len);
709
710 purple_cipher_context_reset(hash, NULL);
711
712 purple_cipher_context_append(hash, hctx->opad, hctx->blocksize);
713 purple_cipher_context_append(hash, inner_hash, hash_len);
714
715 g_free(inner_hash);
716
717 result = result && purple_cipher_context_digest(hash, in_len, out, out_len);
718
719 return result;
720 }
721
722 static void
723 hmac_uninit(PurpleCipherContext *context)
724 {
725 struct HMAC_Context *hctx;
726
727 purple_cipher_context_reset(context, NULL);
728
729 hctx = purple_cipher_context_get_data(context);
730
731 g_free(hctx);
732 }
733
734 static void
735 hmac_set_key_with_len(PurpleCipherContext *context, const guchar * key, size_t key_len)
736 {
737 struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
738 int blocksize, i;
739 guchar *ipad;
740 guchar *full_key;
741
742 g_return_if_fail(hctx->hash != NULL);
743
744 g_free(hctx->opad);
745
746 blocksize = hctx->blocksize;
747 ipad = g_malloc(blocksize);
748 hctx->opad = g_malloc(blocksize);
749
750 if (key_len > blocksize) {
751 purple_cipher_context_reset(hctx->hash, NULL);
752 purple_cipher_context_append(hctx->hash, key, key_len);
753 full_key = g_malloc(100); /* TODO: Should be enough for now... */
754 purple_cipher_context_digest(hctx->hash, 100, full_key, &key_len);
755 } else
756 full_key = g_memdup(key, key_len);
757
758 if (key_len < blocksize) {
759 full_key = g_realloc(full_key, blocksize);
760 memset(full_key + key_len, 0, blocksize - key_len);
761 }
762
763 for(i = 0; i < blocksize; i++) {
764 ipad[i] = 0x36 ^ full_key[i];
765 hctx->opad[i] = 0x5c ^ full_key[i];
766 }
767
768 g_free(full_key);
769
770 purple_cipher_context_reset(hctx->hash, NULL);
771 purple_cipher_context_append(hctx->hash, ipad, blocksize);
772 g_free(ipad);
773 }
774
775 static void
776 hmac_set_key(PurpleCipherContext *context, const guchar * key)
777 {
778 hmac_set_key_with_len(context, key, strlen(key));
779 }
780
781 static size_t
782 hmac_get_block_size(PurpleCipherContext *context)
783 {
784 struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
785
786 return hctx->blocksize;
787 }
788
789 static PurpleCipherOps HMACOps = {
790 hmac_set_opt, /* Set option */
791 hmac_get_opt, /* Get option */
792 hmac_init, /* init */
793 hmac_reset, /* reset */
794 hmac_uninit, /* uninit */
795 NULL, /* set iv */
796 hmac_append, /* append */
797 hmac_digest, /* digest */
798 NULL, /* encrypt */
799 NULL, /* decrypt */
800 NULL, /* set salt */
801 NULL, /* get salt size */
802 hmac_set_key, /* set key */
803 NULL, /* get key size */
804 NULL, /* set batch mode */
805 NULL, /* get batch mode */
806 hmac_get_block_size, /* get block size */
807 hmac_set_key_with_len /* set key with len */
604 }; 808 };
605 809
606 /****************************************************************************** 810 /******************************************************************************
607 * DES 811 * DES
608 *****************************************************************************/ 812 *****************************************************************************/
1049 NULL, /* get salt size */ 1253 NULL, /* get salt size */
1050 des_set_key, /* set key */ 1254 des_set_key, /* set key */
1051 NULL, /* get key size */ 1255 NULL, /* get key size */
1052 NULL, /* set batch mode */ 1256 NULL, /* set batch mode */
1053 NULL, /* get batch mode */ 1257 NULL, /* get batch mode */
1054 1258 NULL, /* get block size */
1055 /* padding */ 1259 NULL /* set key with len */
1056 NULL,
1057 NULL
1058 }; 1260 };
1059 1261
1060 /****************************************************************************** 1262 /******************************************************************************
1061 * Triple-DES 1263 * Triple-DES
1062 *****************************************************************************/ 1264 *****************************************************************************/
1401 NULL, /* get salt size */ 1603 NULL, /* get salt size */
1402 des3_set_key, /* set key */ 1604 des3_set_key, /* set key */
1403 NULL, /* get key size */ 1605 NULL, /* get key size */
1404 des3_set_batch, /* set batch mode */ 1606 des3_set_batch, /* set batch mode */
1405 des3_get_batch, /* get batch mode */ 1607 des3_get_batch, /* get batch mode */
1406 1608 NULL, /* get block size */
1407 /* padding */ 1609 NULL /* set key with len */
1408 NULL,
1409 NULL
1410 }; 1610 };
1411 1611
1412 /******************************************************************************* 1612 /*******************************************************************************
1413 * SHA-1 1613 * SHA-1
1414 ******************************************************************************/ 1614 ******************************************************************************/
1615 #define SHA1_HMAC_BLOCK_SIZE 64
1415 #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF) 1616 #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF)
1416 1617
1417 struct SHA1Context { 1618 struct SHA1Context {
1418 guint32 H[5]; 1619 guint32 H[5];
1419 guint32 W[80]; 1620 guint32 W[80];
1628 1829
1629 if(out_len) 1830 if(out_len)
1630 *out_len = 20; 1831 *out_len = 20;
1631 1832
1632 return TRUE; 1833 return TRUE;
1834 }
1835
1836 static size_t
1837 sha1_get_block_size(PurpleCipherContext *context)
1838 {
1839 /* This does not change (in this case) */
1840 return SHA1_HMAC_BLOCK_SIZE;
1633 } 1841 }
1634 1842
1635 static PurpleCipherOps SHA1Ops = { 1843 static PurpleCipherOps SHA1Ops = {
1636 sha1_set_opt, /* Set Option */ 1844 sha1_set_opt, /* Set Option */
1637 sha1_get_opt, /* Get Option */ 1845 sha1_get_opt, /* Get Option */
1647 NULL, /* get salt size */ 1855 NULL, /* get salt size */
1648 NULL, /* set key */ 1856 NULL, /* set key */
1649 NULL, /* get key size */ 1857 NULL, /* get key size */
1650 NULL, /* set batch mode */ 1858 NULL, /* set batch mode */
1651 NULL, /* get batch mode */ 1859 NULL, /* get batch mode */
1652 1860 sha1_get_block_size, /* get block size */
1653 /* padding */ 1861 NULL /* set key with len */
1654 NULL,
1655 NULL
1656 }; 1862 };
1657 1863
1658 /******************************************************************************* 1864 /*******************************************************************************
1659 * RC4 1865 * RC4
1660 ******************************************************************************/ 1866 ******************************************************************************/
1816 NULL, /* get salt size */ 2022 NULL, /* get salt size */
1817 rc4_set_key, /* set key */ 2023 rc4_set_key, /* set key */
1818 rc4_get_key_size, /* get key size */ 2024 rc4_get_key_size, /* get key size */
1819 NULL, /* set batch mode */ 2025 NULL, /* set batch mode */
1820 NULL, /* get batch mode */ 2026 NULL, /* get batch mode */
1821 2027 NULL, /* get block size */
1822 /* padding */ 2028 NULL /* set key with len */
1823 NULL,
1824 NULL
1825 }; 2029 };
1826 2030
1827 /******************************************************************************* 2031 /*******************************************************************************
1828 * Structs 2032 * Structs
1829 ******************************************************************************/ 2033 ******************************************************************************/
1893 caps |= PURPLE_CIPHER_CAPS_GET_KEY_SIZE; 2097 caps |= PURPLE_CIPHER_CAPS_GET_KEY_SIZE;
1894 if(ops->set_batch_mode) 2098 if(ops->set_batch_mode)
1895 caps |= PURPLE_CIPHER_CAPS_SET_BATCH_MODE; 2099 caps |= PURPLE_CIPHER_CAPS_SET_BATCH_MODE;
1896 if(ops->get_batch_mode) 2100 if(ops->get_batch_mode)
1897 caps |= PURPLE_CIPHER_CAPS_GET_BATCH_MODE; 2101 caps |= PURPLE_CIPHER_CAPS_GET_BATCH_MODE;
2102 if(ops->get_block_size)
2103 caps |= PURPLE_CIPHER_CAPS_GET_BLOCK_SIZE;
2104 if(ops->set_key_with_len)
2105 caps |= PURPLE_CIPHER_CAPS_SET_KEY_WITH_LEN;
1898 2106
1899 return caps; 2107 return caps;
1900 } 2108 }
1901 2109
1902 gboolean 2110 gboolean
2019 PURPLE_SUBTYPE_CIPHER)); 2227 PURPLE_SUBTYPE_CIPHER));
2020 2228
2021 purple_ciphers_register_cipher("md5", &MD5Ops); 2229 purple_ciphers_register_cipher("md5", &MD5Ops);
2022 purple_ciphers_register_cipher("sha1", &SHA1Ops); 2230 purple_ciphers_register_cipher("sha1", &SHA1Ops);
2023 purple_ciphers_register_cipher("md4", &MD4Ops); 2231 purple_ciphers_register_cipher("md4", &MD4Ops);
2232 purple_ciphers_register_cipher("hmac", &HMACOps);
2024 purple_ciphers_register_cipher("des", &DESOps); 2233 purple_ciphers_register_cipher("des", &DESOps);
2025 purple_ciphers_register_cipher("des3", &DES3Ops); 2234 purple_ciphers_register_cipher("des3", &DES3Ops);
2026 purple_ciphers_register_cipher("rc4", &RC4Ops); 2235 purple_ciphers_register_cipher("rc4", &RC4Ops);
2027 } 2236 }
2028 2237
2385 else { 2594 else {
2386 purple_debug_info("cipher", "The %s cipher does not support the " 2595 purple_debug_info("cipher", "The %s cipher does not support the "
2387 "get_batch_mode operation\n", cipher->name); 2596 "get_batch_mode operation\n", cipher->name);
2388 return -1; 2597 return -1;
2389 } 2598 }
2599 }
2600
2601 size_t
2602 purple_cipher_context_get_block_size(PurpleCipherContext *context)
2603 {
2604 PurpleCipher *cipher = NULL;
2605
2606 g_return_val_if_fail(context, -1);
2607
2608 cipher = context->cipher;
2609 g_return_val_if_fail(cipher, -1);
2610
2611 if(cipher->ops && cipher->ops->get_block_size)
2612 return cipher->ops->get_block_size(context);
2613 else {
2614 purple_debug_info("cipher", "The %s cipher does not support the "
2615 "get_block_size operation\n", cipher->name);
2616 return -1;
2617 }
2618 }
2619
2620 void
2621 purple_cipher_context_set_key_with_len(PurpleCipherContext *context,
2622 const guchar *key, size_t len)
2623 {
2624 PurpleCipher *cipher = NULL;
2625
2626 g_return_if_fail(context);
2627
2628 cipher = context->cipher;
2629 g_return_if_fail(cipher);
2630
2631 if(cipher->ops && cipher->ops->set_key_with_len)
2632 cipher->ops->set_key_with_len(context, key, len);
2633 else
2634 purple_debug_info("cipher", "The %s cipher does not support the "
2635 "set_key_with_len operation\n", cipher->name);
2390 } 2636 }
2391 2637
2392 void 2638 void
2393 purple_cipher_context_set_data(PurpleCipherContext *context, gpointer data) { 2639 purple_cipher_context_set_data(PurpleCipherContext *context, gpointer data) {
2394 g_return_if_fail(context); 2640 g_return_if_fail(context);