summaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto
Commit message (Expand)AuthorAgeFilesLines
* [S390] use kzfree()Johannes Weiner2009-03-261-2/+1Star
* [S390] list usage cleanup in s390Eric Sesterhenn2009-03-261-4/+2Star
* s390: remove s390_root_dev_*()Mark McLoughlin2009-01-061-4/+3Star
* [S390] convert ap_bus printks to pr_xxx macros.Martin Schwidefsky2008-12-251-3/+7
* [S390] drivers/s390/crypto: Move dereference to after IS_ERR testJulia Lawall2008-12-254-12/+28
* [S390] ap: Minor code beautification.Christian Maaser2008-12-251-14/+14
* [S390] zcrypt: Use of Thin InterruptsFelix Beck2008-12-252-4/+176
* Merge commit 'linus/master' into merge-linusArjan van de Ven2008-10-171-2/+2
|\
| * [S390] bus_id -> dev_set_name() changesCornelia Huck2008-10-101-2/+2
* | hrtimer: convert s390 to the new hrtimer apisArjan van de Ven2008-09-061-3/+3
|/
* Merge branch 'bkl-removal' of git://git.lwn.net/linux-2.6Linus Torvalds2008-07-141-0/+3
|\
| * crypto-zcrypt_api: BKL pushdownArnd Bergmann2008-06-201-0/+3
* | [S390] Cleanup zcrypt printk messages.Felix Beck2008-07-147-130/+17Star
* | [S390] zcrypt: Add additional card IDs to CEX2C and CEX2ARalph Wuerthner2008-07-143-0/+4
* | [S390] ap: Use high-resolution timer for pollingFelix Beck2008-07-141-10/+53
|/
* [S390] zcrypt: Comments and kernel-doc cleanupFelix Beck2008-04-177-95/+184
* [S390] replace remaining __FUNCTION__ occurrencesHarvey Harrison2008-04-171-4/+4
* [S390] zcrypt: add support for large random numbersRalph Wuerthner2008-04-173-1/+326
* [S390] zcrypt: fix ap_device_list handlingRalph Wuerthner2008-03-051-5/+7
* [S390] zcrypt: Do not start ap poll thread per defaultFelix Beck2008-02-091-2/+2
* Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6Linus Torvalds2007-10-131-10/+4Star
|\
| * Driver core: change add_uevent_var to use a structKay Sievers2007-10-121-10/+4Star
* | [S390] zcrypt: fix PCIXCC/CEX2C error recoveryRalph Wuerthner2007-10-121-2/+5
* | [S390] zcrypt: fix ap_reset_domain()Ralph Wuerthner2007-10-121-2/+3
* | [S390] zcrypt: remove duplicated struct CPRBX definitionRalph Wuerthner2007-10-122-46/+1Star
* | [S390] zcrypt: make init/exit functions static.Heiko Carstens2007-10-121-2/+2
|/
* [S390] zcrypt: fix request timeout handlingRalph Wuerthner2007-07-106-90/+140
* uevent: use add_uevent_var() instead of open coding itEric Rannaud2007-04-271-15/+13Star
* [S390] zcrypt: Fix ap_poll_requests counter in lost requests error path.Ralph Wuerthner2007-03-261-0/+4
* [S390] zcrypt: Fix possible dead lock in AP bus module.Ralph Wuerthner2007-03-261-13/+13
* [S390] zcrypt: fix possible race when unloading zcrypt driver modulesRalph Wuerthner2007-03-191-6/+6
* [S390] zcrypt: fix possible dead lock in AP bus moduleRalph Wuerthner2007-03-192-7/+24
* [PATCH] mark struct file_operations const 5Arjan van de Ven2007-02-121-1/+1
* [PATCH] proc: remove useless (and buggy) ->nlink settingsAlexey Dobriyan2007-02-111-1/+0Star
* [S390] Avoid excessive inlining.Heiko Carstens2007-02-053-16/+16
* [S390] Get rid of a lot of sparse warnings.Heiko Carstens2007-02-052-3/+4
* [S390] zcrypt: module unload fixes.Ralph Wuerthner2006-12-151-2/+12
* [PATCH] getting rid of all casts of k[cmz]alloc() callsRobert P. J. Day2006-12-133-5/+5
* [S390] add reset call handler to the ap bus.Ralph Wuerthner2006-12-081-0/+17
* [PATCH] More work_struct induced breakage (s390)Al Viro2006-12-061-3/+3
* [S390] Add MODALIAS= to the uevent for the ap bus.Cornelia Huck2006-12-041-1/+9
* [S390] Improve AP bus device removal.Ralph Wuerthner2006-10-271-1/+6
* [S390] ap bus poll thread priority.Christian Borntraeger2006-10-061-1/+1
* [S390] zcrypt device registration/unregistration race.Ralph Wuerthner2006-10-041-11/+12
* [S390] zcrypt secure key cryptography extension.Ralph Wuerthner2006-09-2013-25/+373
* [S390] zcrypt driver Makefile, Kconfig and monolithic build.Martin Schwidefsky2006-09-202-0/+113
* [S390] zcrypt PCICC, PCIXCC coprocessor card ap bus drivers.Martin Schwidefsky2006-09-205-0/+1949
* [S390] zcrypt CEX2A, CEX2C, PCICA accelerator card ap bus drivers.Martin Schwidefsky2006-09-205-0/+1229
* [S390] zcrypt user space interface.Martin Schwidefsky2006-09-202-0/+1121
* [S390] zcrypt adjunct processor bus.Martin Schwidefsky2006-09-202-0/+1379
52' href='#n652'>652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
/*
 * Cryptographic API.
 *
 * DES & Triple DES EDE Cipher Algorithms.
 *
 * Copyright (c) 2005 Dag Arne Osvik <da@osvik.no>
 *
 * 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.
 *
 */

#include <asm/byteorder.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/crypto.h>
#include <linux/types.h>

#include <crypto/des.h>

#define ROL(x, r) ((x) = rol32((x), (r)))
#define ROR(x, r) ((x) = ror32((x), (r)))

struct des_ctx {
	u32 expkey[DES_EXPKEY_WORDS];
};

struct des3_ede_ctx {
	u32 expkey[DES3_EDE_EXPKEY_WORDS];
};

/* Lookup tables for key expansion */

static const u8 pc1[256] = {
	0x00, 0x00, 0x40, 0x04, 0x10, 0x10, 0x50, 0x14,
	0x04, 0x40, 0x44, 0x44, 0x14, 0x50, 0x54, 0x54,
	0x02, 0x02, 0x42, 0x06, 0x12, 0x12, 0x52, 0x16,
	0x06, 0x42, 0x46, 0x46, 0x16, 0x52, 0x56, 0x56,
	0x80, 0x08, 0xc0, 0x0c, 0x90, 0x18, 0xd0, 0x1c,
	0x84, 0x48, 0xc4, 0x4c, 0x94, 0x58, 0xd4, 0x5c,
	0x82, 0x0a, 0xc2, 0x0e, 0x92, 0x1a, 0xd2, 0x1e,
	0x86, 0x4a, 0xc6, 0x4e, 0x96, 0x5a, 0xd6, 0x5e,
	0x20, 0x20, 0x60, 0x24, 0x30, 0x30, 0x70, 0x34,
	0x24, 0x60, 0x64, 0x64, 0x34, 0x70, 0x74, 0x74,
	0x22, 0x22, 0x62, 0x26, 0x32, 0x32, 0x72, 0x36,
	0x26, 0x62, 0x66, 0x66, 0x36, 0x72, 0x76, 0x76,
	0xa0, 0x28, 0xe0, 0x2c, 0xb0, 0x38, 0xf0, 0x3c,
	0xa4, 0x68, 0xe4, 0x6c, 0xb4, 0x78, 0xf4, 0x7c,
	0xa2, 0x2a, 0xe2, 0x2e, 0xb2, 0x3a, 0xf2, 0x3e,
	0xa6, 0x6a, 0xe6, 0x6e, 0xb6, 0x7a, 0xf6, 0x7e,
	0x08, 0x80, 0x48, 0x84, 0x18, 0x90, 0x58, 0x94,
	0x0c, 0xc0, 0x4c, 0xc4, 0x1c, 0xd0, 0x5c, 0xd4,
	0x0a, 0x82, 0x4a, 0x86, 0x1a, 0x92, 0x5a, 0x96,
	0x0e, 0xc2, 0x4e, 0xc6, 0x1e, 0xd2, 0x5e, 0xd6,
	0x88, 0x88, 0xc8, 0x8c, 0x98, 0x98, 0xd8, 0x9c,
	0x8c, 0xc8, 0xcc, 0xcc, 0x9c, 0xd8, 0xdc, 0xdc,
	0x8a, 0x8a, 0xca, 0x8e, 0x9a, 0x9a, 0xda, 0x9e,
	0x8e, 0xca, 0xce, 0xce, 0x9e, 0xda, 0xde, 0xde,
	0x28, 0xa0, 0x68, 0xa4, 0x38, 0xb0, 0x78, 0xb4,
	0x2c, 0xe0, 0x6c, 0xe4, 0x3c, 0xf0, 0x7c, 0xf4,
	0x2a, 0xa2, 0x6a, 0xa6, 0x3a, 0xb2, 0x7a, 0xb6,
	0x2e, 0xe2, 0x6e, 0xe6, 0x3e, 0xf2, 0x7e, 0xf6,
	0xa8, 0xa8, 0xe8, 0xac, 0xb8, 0xb8, 0xf8, 0xbc,
	0xac, 0xe8, 0xec, 0xec, 0xbc, 0xf8, 0xfc, 0xfc,
	0xaa, 0xaa, 0xea, 0xae, 0xba, 0xba, 0xfa, 0xbe,
	0xae, 0xea, 0xee, 0xee, 0xbe, 0xfa, 0xfe, 0xfe
};

static const u8 rs[256] = {
	0x00, 0x00, 0x80, 0x80, 0x02, 0x02, 0x82, 0x82,
	0x04, 0x04, 0x84, 0x84, 0x06, 0x06, 0x86, 0x86,
	0x08, 0x08, 0x88, 0x88, 0x0a, 0x0a, 0x8a, 0x8a,
	0x0c, 0x0c, 0x8c, 0x8c, 0x0e, 0x0e, 0x8e, 0x8e,
	0x10, 0x10, 0x90, 0x90, 0x12, 0x12, 0x92, 0x92,
	0x14, 0x14, 0x94, 0x94, 0x16, 0x16, 0x96, 0x96,
	0x18, 0x18, 0x98, 0x98, 0x1a, 0x1a, 0x9a, 0x9a,
	0x1c, 0x1c, 0x9c, 0x9c, 0x1e, 0x1e, 0x9e, 0x9e,
	0x20, 0x20, 0xa0, 0xa0, 0x22, 0x22, 0xa2, 0xa2,
	0x24, 0x24, 0xa4, 0xa4, 0x26, 0x26, 0xa6, 0xa6,
	0x28, 0x28, 0xa8, 0xa8, 0x2a, 0x2a, 0xaa, 0xaa,
	0x2c, 0x2c, 0xac, 0xac, 0x2e, 0x2e, 0xae, 0xae,
	0x30, 0x30, 0xb0, 0xb0, 0x32, 0x32, 0xb2, 0xb2,
	0x34, 0x34, 0xb4, 0xb4, 0x36, 0x36, 0xb6, 0xb6,
	0x38, 0x38, 0xb8, 0xb8, 0x3a, 0x3a, 0xba, 0xba,
	0x3c, 0x3c, 0xbc, 0xbc, 0x3e, 0x3e, 0xbe, 0xbe,
	0x40, 0x40, 0xc0, 0xc0, 0x42, 0x42, 0xc2, 0xc2,
	0x44, 0x44, 0xc4, 0xc4, 0x46, 0x46, 0xc6, 0xc6,
	0x48, 0x48, 0xc8, 0xc8, 0x4a, 0x4a, 0xca, 0xca,
	0x4c, 0x4c, 0xcc, 0xcc, 0x4e, 0x4e, 0xce, 0xce,
	0x50, 0x50, 0xd0, 0xd0, 0x52, 0x52, 0xd2, 0xd2,
	0x54, 0x54, 0xd4, 0xd4, 0x56, 0x56, 0xd6, 0xd6,
	0x58, 0x58, 0xd8, 0xd8, 0x5a, 0x5a, 0xda, 0xda,
	0x5c, 0x5c, 0xdc, 0xdc, 0x5e, 0x5e, 0xde, 0xde,
	0x60, 0x60, 0xe0, 0xe0, 0x62, 0x62, 0xe2, 0xe2,
	0x64, 0x64, 0xe4, 0xe4, 0x66, 0x66, 0xe6, 0xe6,
	0x68, 0x68, 0xe8, 0xe8, 0x6a, 0x6a, 0xea, 0xea,
	0x6c, 0x6c, 0xec, 0xec, 0x6e, 0x6e, 0xee, 0xee,
	0x70, 0x70, 0xf0, 0xf0, 0x72, 0x72, 0xf2, 0xf2,
	0x74, 0x74, 0xf4, 0xf4, 0x76, 0x76, 0xf6, 0xf6,
	0x78, 0x78, 0xf8, 0xf8, 0x7a, 0x7a, 0xfa, 0xfa,
	0x7c, 0x7c, 0xfc, 0xfc, 0x7e, 0x7e, 0xfe, 0xfe
};

static const u32 pc2[1024] = {
	0x00000000, 0x00000000, 0x00000000, 0x00000000,
	0x00040000, 0x00000000, 0x04000000, 0x00100000,
	0x00400000, 0x00000008, 0x00000800, 0x40000000,
	0x00440000, 0x00000008, 0x04000800, 0x40100000,
	0x00000400, 0x00000020, 0x08000000, 0x00000100,
	0x00040400, 0x00000020, 0x0c000000, 0x00100100,
	0x00400400, 0x00000028, 0x08000800, 0x40000100,
	0x00440400, 0x00000028, 0x0c000800, 0x40100100,
	0x80000000, 0x00000010, 0x00000000, 0x00800000,
	0x80040000, 0x00000010, 0x04000000, 0x00900000,
	0x80400000, 0x00000018, 0x00000800, 0x40800000,
	0x80440000, 0x00000018, 0x04000800, 0x40900000,
	0x80000400, 0x00000030, 0x08000000, 0x00800100,
	0x80040400, 0x00000030, 0x0c000000, 0x00900100,
	0x80400400, 0x00000038, 0x08000800, 0x40800100,
	0x80440400, 0x00000038, 0x0c000800, 0x40900100,
	0x10000000, 0x00000000, 0x00200000, 0x00001000,
	0x10040000, 0x00000000, 0x04200000, 0x00101000,
	0x10400000, 0x00000008, 0x00200800, 0x40001000,
	0x10440000, 0x00000008, 0x04200800, 0x40101000,
	0x10000400, 0x00000020, 0x08200000, 0x00001100,
	0x10040400, 0x00000020, 0x0c200000, 0x00101100,
	0x10400400, 0x00000028, 0x08200800, 0x40001100,
	0x10440400, 0x00000028, 0x0c200800, 0x40101100,
	0x90000000, 0x00000010, 0x00200000, 0x00801000,
	0x90040000, 0x00000010, 0x04200000, 0x00901000,
	0x90400000, 0x00000018, 0x00200800, 0x40801000,
	0x90440000, 0x00000018, 0x04200800, 0x40901000,
	0x90000400, 0x00000030, 0x08200000, 0x00801100,
	0x90040400, 0x00000030, 0x0c200000, 0x00901100,
	0x90400400, 0x00000038, 0x08200800, 0x40801100,
	0x90440400, 0x00000038, 0x0c200800, 0x40901100,
	0x00000200, 0x00080000, 0x00000000, 0x00000004,
	0x00040200, 0x00080000, 0x04000000, 0x00100004,
	0x00400200, 0x00080008, 0x00000800, 0x40000004,
	0x00440200, 0x00080008, 0x04000800, 0x40100004,
	0x00000600, 0x00080020, 0x08000000, 0x00000104,
	0x00040600, 0x00080020, 0x0c000000, 0x00100104,
	0x00400600, 0x00080028, 0x08000800, 0x40000104,
	0x00440600, 0x00080028, 0x0c000800, 0x40100104,
	0x80000200, 0x00080010, 0x00000000, 0x00800004,
	0x80040200, 0x00080010, 0x04000000, 0x00900004,
	0x80400200, 0x00080018, 0x00000800, 0x40800004,
	0x80440200, 0x00080018, 0x04000800, 0x40900004,
	0x80000600, 0x00080030, 0x08000000, 0x00800104,
	0x80040600, 0x00080030, 0x0c000000, 0x00900104,
	0x80400600, 0x00080038, 0x08000800, 0x40800104,
	0x80440600, 0x00080038, 0x0c000800, 0x40900104,
	0x10000200, 0x00080000, 0x00200000, 0x00001004,
	0x10040200, 0x00080000, 0x04200000, 0x00101004,
	0x10400200, 0x00080008, 0x00200800, 0x40001004,
	0x10440200, 0x00080008, 0x04200800, 0x40101004,
	0x10000600, 0x00080020, 0x08200000, 0x00001104,
	0x10040600, 0x00080020, 0x0c200000, 0x00101104,
	0x10400600, 0x00080028, 0x08200800, 0x40001104,
	0x10440600, 0x00080028, 0x0c200800, 0x40101104,
	0x90000200, 0x00080010, 0x00200000, 0x00801004,
	0x90040200, 0x00080010, 0x04200000, 0x00901004,
	0x90400200, 0x00080018, 0x00200800, 0x40801004,
	0x90440200, 0x00080018, 0x04200800, 0x40901004,
	0x90000600, 0x00080030, 0x08200000, 0x00801104,
	0x90040600, 0x00080030, 0x0c200000, 0x00901104,
	0x90400600, 0x00080038, 0x08200800, 0x40801104,
	0x90440600, 0x00080038, 0x0c200800, 0x40901104,
	0x00000002, 0x00002000, 0x20000000, 0x00000001,
	0x00040002, 0x00002000, 0x24000000, 0x00100001,
	0x00400002, 0x00002008, 0x20000800, 0x40000001,
	0x00440002, 0x00002008, 0x24000800, 0x40100001,
	0x00000402, 0x00002020, 0x28000000, 0x00000101,
	0x00040402, 0x00002020, 0x2c000000, 0x00100101,
	0x00400402, 0x00002028, 0x28000800, 0x40000101,
	0x00440402, 0x00002028, 0x2c000800, 0x40100101,
	0x80000002, 0x00002010, 0x20000000, 0x00800001,
	0x80040002, 0x00002010, 0x24000000, 0x00900001,
	0x80400002, 0x00002018, 0x20000800, 0x40800001,
	0x80440002, 0x00002018, 0x24000800, 0x40900001,
	0x80000402, 0x00002030, 0x28000000, 0x00800101,
	0x80040402, 0x00002030, 0x2c000000, 0x00900101,
	0x80400402, 0x00002038, 0x28000800, 0x40800101,
	0x80440402, 0x00002038, 0x2c000800, 0x40900101,
	0x10000002, 0x00002000, 0x20200000, 0x00001001,
	0x10040002, 0x00002000, 0x24200000, 0x00101001,
	0x10400002, 0x00002008, 0x20200800, 0x40001001,
	0x10440002, 0x00002008, 0x24200800, 0x40101001,
	0x10000402, 0x00002020, 0x28200000, 0x00001101,
	0x10040402, 0x00002020, 0x2c200000, 0x00101101,
	0x10400402, 0x00002028, 0x28200800, 0x40001101,
	0x10440402, 0x00002028, 0x2c200800, 0x40101101,
	0x90000002, 0x00002010, 0x20200000, 0x00801001,
	0x90040002, 0x00002010, 0x24200000, 0x00901001,
	0x90400002, 0x00002018, 0x20200800, 0x40801001,
	0x90440002, 0x00002018, 0x24200800, 0x40901001,
	0x90000402, 0x00002030, 0x28200000, 0x00801101,
	0x90040402, 0x00002030, 0x2c200000, 0x00901101,
	0x90400402, 0x00002038, 0x28200800, 0x40801101,
	0x90440402, 0x00002038, 0x2c200800, 0x40901101,
	0x00000202, 0x00082000, 0x20000000, 0x00000005,
	0x00040202, 0x00082000, 0x24000000, 0x00100005,
	0x00400202, 0x00082008, 0x20000800, 0x40000005,
	0x00440202, 0x00082008, 0x24000800, 0x40100005,
	0x00000602, 0x00082020, 0x28000000, 0x00000105,
	0x00040602, 0x00082020, 0x2c000000, 0x00100105,
	0x00400602, 0x00082028, 0x28000800, 0x40000105,
	0x00440602, 0x00082028, 0x2c000800, 0x40100105,
	0x80000202, 0x00082010, 0x20000000, 0x00800005,
	0x80040202, 0x00082010, 0x24000000, 0x00900005,
	0x80400202, 0x00082018, 0x20000800, 0x40800005,
	0x80440202, 0x00082018, 0x24000800, 0x40900005,
	0x80000602, 0x00082030, 0x28000000, 0x00800105,
	0x80040602, 0x00082030, 0x2c000000, 0x00900105,
	0x80400602, 0x00082038, 0x28000800, 0x40800105,
	0x80440602, 0x00082038, 0x2c000800, 0x40900105,
	0x10000202, 0x00082000, 0x20200000, 0x00001005,
	0x10040202, 0x00082000, 0x24200000, 0x00101005,
	0x10400202, 0x00082008, 0x20200800, 0x40001005,
	0x10440202, 0x00082008, 0x24200800, 0x40101005,
	0x10000602, 0x00082020, 0x28200000, 0x00001105,
	0x10040602, 0x00082020, 0x2c200000, 0x00101105,
	0x10400602, 0x00082028, 0x28200800, 0x40001105,
	0x10440602, 0x00082028, 0x2c200800, 0x40101105,
	0x90000202, 0x00082010, 0x20200000, 0x00801005,
	0x90040202, 0x00082010, 0x24200000, 0x00901005,
	0x90400202, 0x00082018, 0x20200800, 0x40801005,
	0x90440202, 0x00082018, 0x24200800, 0x40901005,
	0x90000602, 0x00082030, 0x28200000, 0x00801105,
	0x90040602, 0x00082030, 0x2c200000, 0x00901105,
	0x90400602, 0x00082038, 0x28200800, 0x40801105,
	0x90440602, 0x00082038, 0x2c200800, 0x40901105,

	0x00000000, 0x00000000, 0x00000000, 0x00000000,
	0x00000000, 0x00000008, 0x00080000, 0x10000000,
	0x02000000, 0x00000000, 0x00000080, 0x00001000,
	0x02000000, 0x00000008, 0x00080080, 0x10001000,
	0x00004000, 0x00000000, 0x00000040, 0x00040000,
	0x00004000, 0x00000008, 0x00080040, 0x10040000,
	0x02004000, 0x00000000, 0x000000c0, 0x00041000,
	0x02004000, 0x00000008, 0x000800c0, 0x10041000,
	0x00020000, 0x00008000, 0x08000000, 0x00200000,
	0x00020000, 0x00008008, 0x08080000, 0x10200000,
	0x02020000, 0x00008000, 0x08000080, 0x00201000,
	0x02020000, 0x00008008, 0x08080080, 0x10201000,
	0x00024000, 0x00008000, 0x08000040, 0x00240000,
	0x00024000, 0x00008008, 0x08080040, 0x10240000,
	0x02024000, 0x00008000, 0x080000c0, 0x00241000,
	0x02024000, 0x00008008, 0x080800c0, 0x10241000,
	0x00000000, 0x01000000, 0x00002000, 0x00000020,
	0x00000000, 0x01000008, 0x00082000, 0x10000020,
	0x02000000, 0x01000000, 0x00002080, 0x00001020,
	0x02000000, 0x01000008, 0x00082080, 0x10001020,
	0x00004000, 0x01000000, 0x00002040, 0x00040020,
	0x00004000, 0x01000008, 0x00082040, 0x10040020,
	0x02004000, 0x01000000, 0x000020c0, 0x00041020,
	0x02004000, 0x01000008, 0x000820c0, 0x10041020,
	0x00020000, 0x01008000, 0x08002000, 0x00200020,
	0x00020000, 0x01008008, 0x08082000, 0x10200020,
	0x02020000, 0x01008000, 0x08002080, 0x00201020,
	0x02020000, 0x01008008, 0x08082080, 0x10201020,
	0x00024000, 0x01008000, 0x08002040, 0x00240020,
	0x00024000, 0x01008008, 0x08082040, 0x10240020,
	0x02024000, 0x01008000, 0x080020c0, 0x00241020,
	0x02024000, 0x01008008, 0x080820c0, 0x10241020,
	0x00000400, 0x04000000, 0x00100000, 0x00000004,
	0x00000400, 0x04000008, 0x00180000, 0x10000004,
	0x02000400, 0x04000000, 0x00100080, 0x00001004,
	0x02000400, 0x04000008, 0x00180080, 0x10001004,
	0x00004400, 0x04000000, 0x00100040, 0x00040004,
	0x00004400, 0x04000008, 0x00180040, 0x10040004,
	0x02004400, 0x04000000, 0x001000c0, 0x00041004,
	0x02004400, 0x04000008, 0x001800c0, 0x10041004,
	0x00020400, 0x04008000, 0x08100000, 0x00200004,
	0x00020400, 0x04008008, 0x08180000, 0x10200004,
	0x02020400, 0x04008000, 0x08100080, 0x00201004,
	0x02020400, 0x04008008, 0x08180080, 0x10201004,
	0x00024400, 0x04008000, 0x08100040, 0x00240004,
	0x00024400, 0x04008008, 0x08180040, 0x10240004,
	0x02024400, 0x04008000, 0x081000c0, 0x00241004,
	0x02024400, 0x04008008, 0x081800c0, 0x10241004,
	0x00000400, 0x05000000, 0x00102000, 0x00000024,
	0x00000400, 0x05000008, 0x00182000, 0x10000024,
	0x02000400, 0x05000000, 0x00102080, 0x00001024,
	0x02000400, 0x05000008, 0x00182080, 0x10001024,
	0x00004400, 0x05000000, 0x00102040, 0x00040024,
	0x00004400, 0x05000008, 0x00182040, 0x10040024,
	0x02004400, 0x05000000, 0x001020c0, 0x00041024,
	0x02004400, 0x05000008, 0x001820c0, 0x10041024,
	0x00020400, 0x05008000, 0x08102000, 0x00200024,
	0x00020400, 0x05008008, 0x08182000, 0x10200024,
	0x02020400, 0x05008000, 0x08102080, 0x00201024,
	0x02020400, 0x05008008, 0x08182080, 0x10201024,
	0x00024400, 0x05008000, 0x08102040, 0x00240024,
	0x00024400, 0x05008008, 0x08182040, 0x10240024,
	0x02024400, 0x05008000, 0x081020c0, 0x00241024,
	0x02024400, 0x05008008, 0x081820c0, 0x10241024,
	0x00000800, 0x00010000, 0x20000000, 0x00000010,
	0x00000800, 0x00010008, 0x20080000, 0x10000010,
	0x02000800, 0x00010000, 0x20000080, 0x00001010,
	0x02000800, 0x00010008, 0x20080080, 0x10001010,
	0x00004800, 0x00010000, 0x20000040, 0x00040010,
	0x00004800, 0x00010008, 0x20080040, 0x10040010,
	0x02004800, 0x00010000, 0x200000c0, 0x00041010,
	0x02004800, 0x00010008, 0x200800c0, 0x10041010,
	0x00020800, 0x00018000, 0x28000000, 0x00200010,
	0x00020800, 0x00018008, 0x28080000, 0x10200010,
	0x02020800, 0x00018000, 0x28000080, 0x00201010,
	0x02020800, 0x00018008, 0x28080080, 0x10201010,
	0x00024800, 0x00018000, 0x28000040, 0x00240010,
	0x00024800, 0x00018008, 0x28080040, 0x10240010,
	0x02024800, 0x00018000, 0x280000c0, 0x00241010,
	0x02024800, 0x00018008, 0x280800c0, 0x10241010,
	0x00000800, 0x01010000, 0x20002000, 0x00000030,
	0x00000800, 0x01010008, 0x20082000, 0x10000030,
	0x02000800, 0x01010000, 0x20002080, 0x00001030,
	0x02000800, 0x01010008, 0x20082080, 0x10001030,
	0x00004800, 0x01010000, 0x20002040, 0x00040030,
	0x00004800, 0x01010008, 0x20082040, 0x10040030,
	0x02004800, 0x01010000, 0x200020c0, 0x00041030,
	0x02004800, 0x01010008, 0x200820c0, 0x10041030,
	0x00020800, 0x01018000, 0x28002000, 0x00200030,
	0x00020800, 0x01018008, 0x28082000, 0x10200030,
	0x02020800, 0x01018000, 0x28002080, 0x00201030,
	0x02020800, 0x01018008, 0x28082080, 0x10201030,
	0x00024800, 0x01018000, 0x28002040, 0x00240030,
	0x00024800, 0x01018008, 0x28082040, 0x10240030,
	0x02024800, 0x01018000, 0x280020c0, 0x00241030,
	0x02024800, 0x01018008, 0x280820c0, 0x10241030,
	0x00000c00, 0x04010000, 0x20100000, 0x00000014,
	0x00000c00, 0x04010008, 0x20180000, 0x10000014,
	0x02000c00, 0x04010000, 0x20100080, 0x00001014,
	0x02000c00, 0x04010008, 0x20180080, 0x10001014,
	0x00004c00, 0x04010000, 0x20100040, 0x00040014,
	0x00004c00, 0x04010008, 0x20180040, 0x10040014,
	0x02004c00, 0x04010000, 0x201000c0, 0x00041014,
	0x02004c00, 0x04010008, 0x201800c0, 0x10041014,
	0x00020c00, 0x04018000, 0x28100000, 0x00200014,
	0x00020c00, 0x04018008, 0x28180000, 0x10200014,
	0x02020c00, 0x04018000, 0x28100080, 0x00201014,
	0x02020c00, 0x04018008, 0x28180080, 0x10201014,
	0x00024c00, 0x04018000, 0x28100040, 0x00240014,
	0x00024c00, 0x04018008, 0x28180040, 0x10240014,
	0x02024c00, 0x04018000, 0x281000c0, 0x00241014,
	0x02024c00, 0x04018008, 0x281800c0, 0x10241014,
	0x00000c00, 0x05010000, 0x20102000, 0x00000034,
	0x00000c00, 0x05010008, 0x20182000, 0x10000034,
	0x02000c00, 0x05010000, 0x20102080, 0x00001034,
	0x02000c00, 0x05010008, 0x20182080, 0x10001034,
	0x00004c00, 0x05010000, 0x20102040, 0x00040034,
	0x00004c00, 0x05010008, 0x20182040, 0x10040034,
	0x02004c00, 0x05010000, 0x201020c0, 0x00041034,
	0x02004c00, 0x05010008, 0x201820c0, 0x10041034,
	0x00020c00, 0x05018000, 0x28102000, 0x00200034,
	0x00020c00, 0x05018008, 0x28182000, 0x10200034,
	0x02020c00, 0x05018000, 0x28102080, 0x00201034,
	0x02020c00, 0x05018008, 0x28182080, 0x10201034,
	0x00024c00, 0x05018000, 0x28102040, 0x00240034,
	0x00024c00, 0x05018008, 0x28182040, 0x10240034,
	0x02024c00, 0x05018000, 0x281020c0, 0x00241034,
	0x02024c00, 0x05018008, 0x281820c0, 0x10241034
};

/* S-box lookup tables */

static const u32 S1[64] = {
	0x01010400, 0x00000000, 0x00010000, 0x01010404,
	0x01010004, 0x00010404, 0x00000004, 0x00010000,
	0x00000400, 0x01010400, 0x01010404, 0x00000400,
	0x01000404, 0x01010004, 0x01000000, 0x00000004,
	0x00000404, 0x01000400, 0x01000400, 0x00010400,
	0x00010400, 0x01010000, 0x01010000, 0x01000404,
	0x00010004, 0x01000004, 0x01000004, 0x00010004,
	0x00000000, 0x00000404, 0x00010404, 0x01000000,
	0x00010000, 0x01010404, 0x00000004, 0x01010000,
	0x01010400, 0x01000000, 0x01000000, 0x00000400,
	0x01010004, 0x00010000, 0x00010400, 0x01000004,
	0x00000400, 0x00000004, 0x01000404, 0x00010404,
	0x01010404, 0x00010004, 0x01010000, 0x01000404,
	0x01000004, 0x00000404, 0x00010404, 0x01010400,
	0x00000404, 0x01000400, 0x01000400, 0x00000000,
	0x00010004, 0x00010400, 0x00000000, 0x01010004
};

static const u32 S2[64] = {
	0x80108020, 0x80008000, 0x00008000, 0x00108020,
	0x00100000, 0x00000020, 0x80100020, 0x80008020,
	0x80000020, 0x80108020, 0x80108000, 0x80000000,
	0x80008000, 0x00100000, 0x00000020, 0x80100020,
	0x00108000, 0x00100020, 0x80008020, 0x00000000,
	0x80000000, 0x00008000, 0x00108020, 0x80100000,
	0x00100020, 0x80000020, 0x00000000, 0x00108000,
	0x00008020, 0x80108000, 0x80100000, 0x00008020,
	0x00000000, 0x00108020, 0x80100020, 0x00100000,
	0x80008020, 0x80100000, 0x80108000, 0x00008000,
	0x80100000, 0x80008000, 0x00000020, 0x80108020,
	0x00108020, 0x00000020, 0x00008000, 0x80000000,
	0x00008020, 0x80108000, 0x00100000, 0x80000020,
	0x00100020, 0x80008020, 0x80000020, 0x00100020,
	0x00108000, 0x00000000, 0x80008000, 0x00008020,
	0x80000000, 0x80100020, 0x80108020, 0x00108000
};

static const u32 S3[64] = {
	0x00000208, 0x08020200, 0x00000000, 0x08020008,
	0x08000200, 0x00000000, 0x00020208, 0x08000200,
	0x00020008, 0x08000008, 0x08000008, 0x00020000,
	0x08020208, 0x00020008, 0x08020000, 0x00000208,
	0x08000000, 0x00000008, 0x08020200, 0x00000200,
	0x00020200, 0x08020000, 0x08020008, 0x00020208,
	0x08000208, 0x00020200, 0x00020000, 0x08000208,
	0x00000008, 0x08020208, 0x00000200, 0x08000000,
	0x08020200, 0x08000000, 0x00020008, 0x00000208,
	0x00020000, 0x08020200, 0x08000200, 0x00000000,
	0x00000200, 0x00020008, 0x08020208, 0x08000200,
	0x08000008, 0x00000200, 0x00000000, 0x08020008,
	0x08000208, 0x00020000, 0x08000000, 0x08020208,
	0x00000008, 0x00020208, 0x00020200, 0x08000008,
	0x08020000, 0x08000208, 0x00000208, 0x08020000,
	0x00020208, 0x00000008, 0x08020008, 0x00020200
};

static const u32 S4[64] = {
	0x00802001, 0x00002081, 0x00002081, 0x00000080,
	0x00802080, 0x00800081, 0x00800001, 0x00002001,
	0x00000000, 0x00802000, 0x00802000, 0x00802081,
	0x00000081, 0x00000000, 0x00800080, 0x00800001,
	0x00000001, 0x00002000, 0x00800000, 0x00802001,
	0x00000080, 0x00800000, 0x00002001, 0x00002080,
	0x00800081, 0x00000001, 0x00002080, 0x00800080,
	0x00002000, 0x00802080, 0x00802081, 0x00000081,
	0x00800080, 0x00800001, 0x00802000, 0x00802081,
	0x00000081, 0x00000000, 0x00000000, 0x00802000,
	0x00002080, 0x00800080, 0x00800081, 0x00000001,
	0x00802001, 0x00002081, 0x00002081, 0x00000080,
	0x00802081, 0x00000081, 0x00000001, 0x00002000,
	0x00800001, 0x00002001, 0x00802080, 0x00800081,
	0x00002001, 0x00002080, 0x00800000, 0x00802001,
	0x00000080, 0x00800000, 0x00002000, 0x00802080
};

static const u32 S5[64] = {
	0x00000100, 0x02080100, 0x02080000, 0x42000100,
	0x00080000, 0x00000100, 0x40000000, 0x02080000,
	0x40080100, 0x00080000, 0x02000100, 0x40080100,
	0x42000100, 0x42080000, 0x00080100, 0x40000000,
	0x02000000, 0x40080000, 0x40080000, 0x00000000,
	0x40000100, 0x42080100, 0x42080100, 0x02000100,
	0x42080000, 0x40000100, 0x00000000, 0x42000000,
	0x02080100, 0x02000000, 0x42000000, 0x00080100,
	0x00080000, 0x42000100, 0x00000100, 0x02000000,
	0x40000000, 0x02080000, 0x42000100, 0x40080100,
	0x02000100, 0x40000000, 0x42080000, 0x02080100,
	0x40080100, 0x00000100, 0x02000000, 0x42080000,
	0x42080100, 0x00080100, 0x42000000, 0x42080100,
	0x02080000, 0x00000000, 0x40080000, 0x42000000,
	0x00080100, 0x02000100, 0x40000100, 0x00080000,
	0x00000000, 0x40080000, 0x02080100, 0x40000100
};

static const u32 S6[64] = {
	0x20000010, 0x20400000, 0x00004000, 0x20404010,
	0x20400000, 0x00000010, 0x20404010, 0x00400000,
	0x20004000, 0x00404010, 0x00400000, 0x20000010,
	0x00400010, 0x20004000, 0x20000000, 0x00004010,
	0x00000000, 0x00400010, 0x20004010, 0x00004000,
	0x00404000, 0x20004010, 0x00000010, 0x20400010,
	0x20400010, 0x00000000, 0x00404010, 0x20404000,
	0x00004010, 0x00404000, 0x20404000, 0x20000000,
	0x20004000, 0x00000010, 0x20400010, 0x00404000,
	0x20404010, 0x00400000, 0x00004010, 0x20000010,
	0x00400000, 0x20004000, 0x20000000, 0x00004010,
	0x20000010, 0x20404010, 0x00404000, 0x20400000,
	0x00404010, 0x20404000, 0x00000000, 0x20400010,
	0x00000010, 0x00004000, 0x20400000, 0x00404010,
	0x00004000, 0x00400010, 0x20004010, 0x00000000,
	0x20404000, 0x20000000, 0x00400010, 0x20004010
};

static const u32 S7[64] = {
	0x00200000, 0x04200002, 0x04000802, 0x00000000,
	0x00000800, 0x04000802, 0x00200802, 0x04200800,
	0x04200802, 0x00200000, 0x00000000, 0x04000002,
	0x00000002, 0x04000000, 0x04200002, 0x00000802,
	0x04000800, 0x00200802, 0x00200002, 0x04000800,
	0x04000002, 0x04200000, 0x04200800, 0x00200002,
	0x04200000, 0x00000800, 0x00000802, 0x04200802,
	0x00200800, 0x00000002, 0x04000000, 0x00200800,
	0x04000000, 0x00200800, 0x00200000, 0x04000802,
	0x04000802, 0x04200002, 0x04200002, 0x00000002,
	0x00200002, 0x04000000, 0x04000800, 0x00200000,
	0x04200800, 0x00000802, 0x00200802, 0x04200800,
	0x00000802, 0x04000002, 0x04200802, 0x04200000,
	0x00200800, 0x00000000, 0x00000002, 0x04200802,
	0x00000000, 0x00200802, 0x04200000, 0x00000800,
	0x04000002, 0x04000800, 0x00000800, 0x00200002
};

static const u32 S8[64] = {
	0x10001040, 0x00001000, 0x00040000, 0x10041040,
	0x10000000, 0x10001040, 0x00000040, 0x10000000,
	0x00040040, 0x10040000, 0x10041040, 0x00041000,
	0x10041000, 0x00041040, 0x00001000, 0x00000040,
	0x10040000, 0x10000040, 0x10001000, 0x00001040,
	0x00041000, 0x00040040, 0x10040040, 0x10041000,
	0x00001040, 0x00000000, 0x00000000, 0x10040040,
	0x10000040, 0x10001000, 0x00041040, 0x00040000,
	0x00041040, 0x00040000, 0x10041000, 0x00001000,
	0x00000040, 0x10040040, 0x00001000, 0x00041040,
	0x10001000, 0x00000040, 0x10000040, 0x10040000,
	0x10040040, 0x10000000, 0x00040000, 0x10001040,
	0x00000000, 0x10041040, 0x00040040, 0x10000040,
	0x10040000, 0x10001000, 0x10001040, 0x00000000,
	0x10041040, 0x00041000, 0x00041000, 0x00001040,
	0x00001040, 0x00040040, 0x10000000, 0x10041000
};

/* Encryption components: IP, FP, and round function */

#define IP(L, R, T)		\
	ROL(R, 4);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xf0f0f0f0;	\
	R ^= L;			\
	L ^= T;			\
	ROL(R, 12);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xffff0000;	\
	R ^= L;			\
	L ^= T;			\
	ROR(R, 14);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xcccccccc;	\
	R ^= L;			\
	L ^= T;			\
	ROL(R, 6);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xff00ff00;	\
	R ^= L;			\
	L ^= T;			\
	ROR(R, 7);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xaaaaaaaa;	\
	R ^= L;			\
	L ^= T;			\
	ROL(L, 1);

#define FP(L, R, T)		\
	ROR(L, 1);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xaaaaaaaa;	\
	R ^= L;			\
	L ^= T;			\
	ROL(R, 7);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xff00ff00;	\
	R ^= L;			\
	L ^= T;			\
	ROR(R, 6);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xcccccccc;	\
	R ^= L;			\
	L ^= T;			\
	ROL(R, 14);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xffff0000;	\
	R ^= L;			\
	L ^= T;			\
	ROR(R, 12);		\
	T  = L;			\
	L ^= R;			\
	L &= 0xf0f0f0f0;	\
	R ^= L;			\
	L ^= T;			\
	ROR(R, 4);

#define ROUND(L, R, A, B, K, d)					\
	B = K[0];			A = K[1];	K += d;	\
	B ^= R;				A ^= R;			\
	B &= 0x3f3f3f3f;		ROR(A, 4);		\
	L ^= S8[0xff & B];		A &= 0x3f3f3f3f;	\
	L ^= S6[0xff & (B >> 8)];	B >>= 16;		\
	L ^= S7[0xff & A];					\
	L ^= S5[0xff & (A >> 8)];	A >>= 16;		\
	L ^= S4[0xff & B];					\
	L ^= S2[0xff & (B >> 8)];				\
	L ^= S3[0xff & A];					\
	L ^= S1[0xff & (A >> 8)];

/*
 * PC2 lookup tables are organized as 2 consecutive sets of 4 interleaved
 * tables of 128 elements.  One set is for C_i and the other for D_i, while
 * the 4 interleaved tables correspond to four 7-bit subsets of C_i or D_i.
 *
 * After PC1 each of the variables a,b,c,d contains a 7 bit subset of C_i
 * or D_i in bits 7-1 (bit 0 being the least significant).
 */

#define T1(x) pt[2 * (x) + 0]
#define T2(x) pt[2 * (x) + 1]
#define T3(x) pt[2 * (x) + 2]
#define T4(x) pt[2 * (x) + 3]

#define DES_PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))

/*
 * Encryption key expansion
 *
 * RFC2451: Weak key checks SHOULD be performed.
 *
 * FIPS 74:
 *
 *   Keys having duals are keys which produce all zeros, all ones, or
 *   alternating zero-one patterns in the C and D registers after Permuted
 *   Choice 1 has operated on the key.
 *
 */
unsigned long des_ekey(u32 *pe, const u8 *k)
{
	/* K&R: long is at least 32 bits */
	unsigned long a, b, c, d, w;
	const u32 *pt = pc2;

	d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d];
	c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c];
	b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
	a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];

	pe[15 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d];
	pe[14 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[13 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[12 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[11 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[10 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 9 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 8 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c];
	pe[ 7 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 6 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[ 5 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 4 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[ 3 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 2 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[ 1 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b];
	pe[ 0 * 2 + 0] = DES_PC2(b, c, d, a);

	/* Check if first half is weak */
	w  = (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);

	/* Skip to next table set */
	pt += 512;

	d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1];
	c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1];
	b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
	a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];

	/* Check if second half is weak */
	w |= (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);

	pe[15 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d];
	pe[14 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[13 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[12 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[11 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[10 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 9 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 8 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c];
	pe[ 7 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 6 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[ 5 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 4 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[ 3 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 2 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[ 1 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b];
	pe[ 0 * 2 + 1] = DES_PC2(b, c, d, a);

	/* Fixup: 2413 5768 -> 1357 2468 */
	for (d = 0; d < 16; ++d) {
		a = pe[2 * d];
		b = pe[2 * d + 1];
		c = a ^ b;
		c &= 0xffff0000;
		a ^= c;
		b ^= c;
		ROL(b, 18);
		pe[2 * d] = a;
		pe[2 * d + 1] = b;
	}

	/* Zero if weak key */
	return w;
}
EXPORT_SYMBOL_GPL(des_ekey);

/*
 * Decryption key expansion
 *
 * No weak key checking is performed, as this is only used by triple DES
 *
 */
static void dkey(u32 *pe, const u8 *k)
{
	/* K&R: long is at least 32 bits */
	unsigned long a, b, c, d;
	const u32 *pt = pc2;

	d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d];
	c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c];
	b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
	a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];

	pe[ 0 * 2] = DES_PC2(a, b, c, d); d = rs[d];
	pe[ 1 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 2 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 3 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 4 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 5 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 6 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 7 * 2] = DES_PC2(d, a, b, c); c = rs[c];
	pe[ 8 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 9 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[10 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[11 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[12 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[13 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[14 * 2] = DES_PC2(c, d, a, b); b = rs[b];
	pe[15 * 2] = DES_PC2(b, c, d, a);

	/* Skip to next table set */
	pt += 512;

	d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1];
	c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1];
	b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
	a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];

	pe[ 0 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d];
	pe[ 1 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 2 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 3 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 4 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 5 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
	pe[ 6 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
	pe[ 7 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c];
	pe[ 8 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[ 9 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[10 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[11 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[12 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
	pe[13 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
	pe[14 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b];
	pe[15 * 2 + 1] = DES_PC2(b, c, d, a);

	/* Fixup: 2413 5768 -> 1357 2468 */
	for (d = 0; d < 16; ++d) {
		a = pe[2 * d];
		b = pe[2 * d + 1];
		c = a ^ b;
		c &= 0xffff0000;
		a ^= c;
		b ^= c;
		ROL(b, 18);
		pe[2 * d] = a;
		pe[2 * d + 1] = b;
	}
}

static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
		      unsigned int keylen)
{
	struct des_ctx *dctx = crypto_tfm_ctx(tfm);
	u32 *flags = &tfm->crt_flags;
	u32 tmp[DES_EXPKEY_WORDS];
	int ret;

	/* Expand to tmp */
	ret = des_ekey(tmp, key);

	if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
		return -EINVAL;
	}

	/* Copy to output */
	memcpy(dctx->expkey, tmp, sizeof(dctx->expkey));

	return 0;
}

static void des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
	struct des_ctx *ctx = crypto_tfm_ctx(tfm);
	const u32 *K = ctx->expkey;
	const __le32 *s = (const __le32 *)src;
	__le32 *d = (__le32 *)dst;
	u32 L, R, A, B;
	int i;

	L = le32_to_cpu(s[0]);
	R = le32_to_cpu(s[1]);

	IP(L, R, A);
	for (i = 0; i < 8; i++) {
		ROUND(L, R, A, B, K, 2);
		ROUND(R, L, A, B, K, 2);
	}
	FP(R, L, A);

	d[0] = cpu_to_le32(R);
	d[1] = cpu_to_le32(L);
}

static void des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
	struct des_ctx *ctx = crypto_tfm_ctx(tfm);
	const u32 *K = ctx->expkey + DES_EXPKEY_WORDS - 2;
	const __le32 *s = (const __le32 *)src;
	__le32 *d = (__le32 *)dst;
	u32 L, R, A, B;
	int i;

	L = le32_to_cpu(s[0]);
	R = le32_to_cpu(s[1]);

	IP(L, R, A);
	for (i = 0; i < 8; i++) {
		ROUND(L, R, A, B, K, -2);
		ROUND(R, L, A, B, K, -2);
	}
	FP(R, L, A);

	d[0] = cpu_to_le32(R);
	d[1] = cpu_to_le32(L);
}

/*
 * RFC2451:
 *
 *   For DES-EDE3, there is no known need to reject weak or
 *   complementation keys.  Any weakness is obviated by the use of
 *   multiple keys.
 *
 *   However, if the first two or last two independent 64-bit keys are
 *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
 *   same as DES.  Implementers MUST reject keys that exhibit this
 *   property.
 *
 */
int __des3_ede_setkey(u32 *expkey, u32 *flags, const u8 *key,
		      unsigned int keylen)
{
	const u32 *K = (const u32 *)key;

	if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
		     !((K[2] ^ K[4]) | (K[3] ^ K[5]))) &&
		     (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
		return -EINVAL;
	}

	des_ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
	dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
	des_ekey(expkey, key);

	return 0;
}
EXPORT_SYMBOL_GPL(__des3_ede_setkey);

static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
			   unsigned int keylen)
{
	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
	u32 *flags = &tfm->crt_flags;
	u32 *expkey = dctx->expkey;

	return __des3_ede_setkey(expkey, flags, key, keylen);
}

static void des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
	const u32 *K = dctx->expkey;
	const __le32 *s = (const __le32 *)src;
	__le32 *d = (__le32 *)dst;
	u32 L, R, A, B;
	int i;

	L = le32_to_cpu(s[0]);
	R = le32_to_cpu(s[1]);

	IP(L, R, A);
	for (i = 0; i < 8; i++) {
		ROUND(L, R, A, B, K, 2);
		ROUND(R, L, A, B, K, 2);
	}
	for (i = 0; i < 8; i++) {
		ROUND(R, L, A, B, K, 2);
		ROUND(L, R, A, B, K, 2);
	}
	for (i = 0; i < 8; i++) {
		ROUND(L, R, A, B, K, 2);
		ROUND(R, L, A, B, K, 2);
	}
	FP(R, L, A);

	d[0] = cpu_to_le32(R);
	d[1] = cpu_to_le32(L);
}

static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
	const u32 *K = dctx->expkey + DES3_EDE_EXPKEY_WORDS - 2;
	const __le32 *s = (const __le32 *)src;
	__le32 *d = (__le32 *)dst;
	u32 L, R, A, B;
	int i;

	L = le32_to_cpu(s[0]);
	R = le32_to_cpu(s[1]);

	IP(L, R, A);
	for (i = 0; i < 8; i++) {
		ROUND(L, R, A, B, K, -2);
		ROUND(R, L, A, B, K, -2);
	}
	for (i = 0; i < 8; i++) {
		ROUND(R, L, A, B, K, -2);
		ROUND(L, R, A, B, K, -2);
	}
	for (i = 0; i < 8; i++) {
		ROUND(L, R, A, B, K, -2);
		ROUND(R, L, A, B, K, -2);
	}
	FP(R, L, A);

	d[0] = cpu_to_le32(R);
	d[1] = cpu_to_le32(L);
}

static struct crypto_alg des_algs[2] = { {
	.cra_name		=	"des",
	.cra_driver_name	=	"des-generic",
	.cra_priority		=	100,
	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
	.cra_blocksize		=	DES_BLOCK_SIZE,
	.cra_ctxsize		=	sizeof(struct des_ctx),
	.cra_module		=	THIS_MODULE,
	.cra_alignmask		=	3,
	.cra_u			=	{ .cipher = {
	.cia_min_keysize	=	DES_KEY_SIZE,
	.cia_max_keysize	=	DES_KEY_SIZE,
	.cia_setkey		=	des_setkey,
	.cia_encrypt		=	des_encrypt,
	.cia_decrypt		=	des_decrypt } }
}, {
	.cra_name		=	"des3_ede",
	.cra_driver_name	=	"des3_ede-generic",
	.cra_priority		=	100,
	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
	.cra_blocksize		=	DES3_EDE_BLOCK_SIZE,
	.cra_ctxsize		=	sizeof(struct des3_ede_ctx),
	.cra_module		=	THIS_MODULE,
	.cra_alignmask		=	3,
	.cra_u			=	{ .cipher = {
	.cia_min_keysize	=	DES3_EDE_KEY_SIZE,
	.cia_max_keysize	=	DES3_EDE_KEY_SIZE,
	.cia_setkey		=	des3_ede_setkey,
	.cia_encrypt		=	des3_ede_encrypt,
	.cia_decrypt		=	des3_ede_decrypt } }
} };

MODULE_ALIAS("des3_ede");

static int __init des_generic_mod_init(void)
{
	return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs));
}

static void __exit des_generic_mod_fini(void)
{
	crypto_unregister_algs(des_algs, ARRAY_SIZE(des_algs));
}

module_init(des_generic_mod_init);
module_exit(des_generic_mod_fini);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
MODULE_AUTHOR("Dag Arne Osvik <da@osvik.no>");
MODULE_ALIAS("des");