• CMAC(GBT 15852.1)和OMAC(RFC4493/NIST SP800-38B)的java实现和测试


    相关标准和文档

    代码下载

    概述

    CMAC, Cipher-based MAC, 即基于AES对称加密算法的MAC,可参考ISO 9797-1标准,其中详细定义了CMAC算法,其对应的国标为《GBT 15852.1》
    最早的CMAC是基于DES的CBC模式构造的MAC,即CBC-MAC,可参考ANSI X9.9ANSI X9.19
    然后 John Black 和 Phillip Rogaway 于2000年提出的避免CBC-MAC安全缺陷的XCBC模式(Extend Cipher Block Chaining Mode),作为CBC模式的扩展,用来构造MAC,即XCBC-MAC
    再后来,Tetsu Iwata 和 Kaoru Kurosawa 基于XCBC-MAC提出了OMAC,即One-Key CBC-MAC,接着又精益求精第提出了OMAC1,前面的OMAC被重新命名为OMAC2,可参考其论文。
    现在提到CMAC通常是指OMAC,而OMAC通常是指OMAC1,可参考NIST SP800-38B标准,也可参考RFC4493文档,其中的测试数据里使用了AES128/192/256算法和3DES算法。
    基于《GBT 15852.1》的算法1和填充1可以实现《GBT 36322》中的SDF_CalculateMAC接口。

    文档说明

    1. ISO 9797: CMAC算法,定义了几种不同MAC算法和填充方式。
    2. GBT 15852.1: 国家标准。2008版本对标ISO 9797-1:1999;2020版本对标ISO 9797-1:2011
    3. X9.9: DES CBC-MAC,其算法对应到“GBT 15852.1”中的“算法1,填充1”。
    4. X9.19: 3DES CBC-MAC,其算法对应到“GBT 15852.1”中的“算法3,填充1”。
    5. SP800-38B: 定义了使用AES和TDEA算法来计算OMAC。

    OMAC

    1. OMAC算法特点

      • 对称算法的CBC向量IV是全0的
      • 在初始化时会根据标准中的子密钥算法生成两个子密钥key1和key2
      • 在处理最后一个分组时,如果是完整的分组,就与key1相异或,然后再加密。如果不是完整的分组,就填充比特串100000000*到完整分组,然后与key2相异或,然后再加密。
    2. 实现

    • BC库中的实现了OMAC算法,底层的实现类为org.bouncycastle.crypto.macs.CMac。对应到《GBT 15852.1-2020》的算法5。在使用时可直接通过java的 Mac 进行使用,算法名称是在相应的对称算法后面添加CMAC

    CMAC:《GBT 15852.1-2020》

    1. 总结
    算法密钥诱导
    (可选;2种)
    消息填充
    (4种)
    初始变换
    (3种)
    最终迭代
    (4种)
    输出变换
    (3种)
    截断操作
    (2种)
    算法1: CBC-MAC1/2/31111
    算法2: EMAC1(可能)1/2/3112-key21
    算法3: ANSI retail MAC1/2/3113-key21
    算法4: MacDES1(可能)1/2/32-K112-key21
    算法5: CMAC/OMAC12413-(K1,K2)11
    算法6: LMAC1(可能)1/2/312-K211
    算法7: TrCBC41112
    算法8: CBCR43411

    ParametersWithPadding类

    ParametersWithPadding类用来设置算法的各种参数。其中定义key1表示需要输入的原始密钥;key2表示在输出变换中使用的密钥,可能是在最开始设置的,也可能是通过密钥诱导生成的。

    public class ParametersWithPadding implements CipherParameters {
        int typeAlg; //算法类型:1~6
        int typePad; //填充类型:1、2、3、4
        int length; //仅 typePad=3 时有效,表示输入数据的总长度
        int transformInit; //初始变换:1、2、3
        int transformOut; //输出变换:1、2、3
        int lastIteration; //最终迭代:1、2、3、4
        int truncate; //截断操作:1、2
        int keyInduce = 1; //密钥诱导方式:0、1;仅用于算法2中。
        byte[] key1;
        byte[] key2;
        byte[] iv;
    
        public ParametersWithPadding(
                byte[] key1, byte[] key2,
                int typeAlg, int typePad) {
            this(key1, key2, typeAlg, typePad, 0);
        }
    
        public ParametersWithPadding(
                byte[] key1, byte[] key2, byte[] iv,
                int typeAlg, int typePad) {
            this(key1, key2, iv, typeAlg, typePad, 0);
        }
    
        public ParametersWithPadding(
                byte[] key1, byte[] key2,
                int typeAlg, int typePad, int length) {
            this(key1, key2, null, typeAlg, typePad, length);
        }
    
        public ParametersWithPadding(
                byte[] key1, byte[] key2, byte[] iv,
                int typeAlg, int typePad, int length) {
            this.key1 = key1;
            this.key2 = key2;
            this.iv = iv;
            this.typeAlg = typeAlg;
            this.typePad = typePad;
            this.length = length;
    
            transformInit = 1;
            transformOut = 1;
            lastIteration = 1;
            truncate = 1;
    
            switch (typeAlg) {
                case 2:
                    transformOut = 2;
                    break;
                case 3:
                    transformOut = 3;
                    //算法3的两个密钥应独立选取;当key2为null时为避免错误,这里将其设置为key1,此时算法3和算法1一致
                    if (this.key2 == null)
                        this.key2 = key1;
                    break;
                case 4:
                    transformInit = 2;
                    transformOut = 2;
                    break;
                case 5:
                    lastIteration = 3;
                    break;
                case 6:
                    lastIteration = 2;
                    break;
                case 7:
                    truncate = 2;
                    break;
                case 8:
                    transformInit = 3;
                    lastIteration = 4;
                    break;
            }
        }
    
        /**
         * 密钥诱导方式,仅用于算法2中。
         * 

    * 默认为1。为了兼容2008标准或验证2008标准的附录测试,需要手动设置为0. * * @param keyInduce 0表示使用2008标准中的密钥诱导;在2008标准中定义,并在附录测试中用到;
    * 1表示使用2020标准中的密钥诱导1。在2020标准中定义,但附录测试中提供了2个密钥,未用到。 */ public void setKeyInduce(int keyInduce) { this.keyInduce = keyInduce; } public CipherParameters getParameters() { if (iv == null) return new KeyParameter(key1); else return new ParametersWithIV(new KeyParameter(key1), iv); }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    YCMac类

    YCMac类中实现了标准中的8种算法。其中定义的K1,表示用在初始变换2或最终迭代3中的密钥;K2表示用在最终迭代2/3中的密钥。
    2020标准中定义的MAC算法的8步操作在YCMac中的处理方法如下:

    • 第1步:密钥诱导: keyInduce
    • 第2步:消息填充: paddingTransform
    • 第3步:数据分割: 在 update 中自动处理
    • 第4步:初始变换: initTransform
    • 第5步:迭代应用分组密码: 在 update 中自动处理
    • 第6步:最终迭代: lastIteration
    • 第7步:输出变换: outTransform
    • 第8步:截断操作: truncate
    public class YCMac implements Mac {
        private final byte[] mac; //mac值
        private final int macSize; //所需的Mac大小
    
        private final byte[] buf; //内部缓冲区
        private int bufOff; //缓冲区当前数据长度
    
        private byte[] K1; //用在初始变换2或最终迭代3中的密钥
        private byte[] K2; //用在最终迭代2/3中的密钥
    
        private final BlockCipher cipher; //底层对称算法对象
        ParametersWithPadding parameters; //算法参数
    
        public YCMac(BlockCipher cipher) {
            this(cipher, cipher.getBlockSize() * 8);
        }
    
        public YCMac(BlockCipher cipher, int macSizeInBits) {
            if ((macSizeInBits % 8) != 0) {
                throw new IllegalArgumentException("MAC size must be multiple of 8");
            }
    
            if (macSizeInBits > (cipher.getBlockSize() * 8)) {
                throw new IllegalArgumentException("MAC size must be less or equal to " + (cipher.getBlockSize() * 8));
            }
    
            this.cipher = new CBCBlockCipher(cipher);
            this.macSize = macSizeInBits / 8;
    
            mac = new byte[cipher.getBlockSize()];
            buf = new byte[cipher.getBlockSize()];
            bufOff = 0;
        }
    
        public String getAlgorithmName() {
            return cipher.getAlgorithmName();
        }
    
        public void init(CipherParameters params) {
            validate(params);
    
            cipher.init(true, parameters.getParameters());
            keyInduce(); //1.密钥诱导
            reset();
    
            //填充方式3:处理在开头添加的填充块
            if (parameters.typePad == 3) {
                byte[] temp = new byte[cipher.getBlockSize()];
                byte[] bLen = Pack.intToBigEndian(parameters.length * 8);
                System.arraycopy(bLen, 0, temp, temp.length - bLen.length, bLen.length);
                update(temp, 0, temp.length);
            }
        }
    
        void validate(CipherParameters params) {
            if (params instanceof ParametersWithPadding)
                parameters = (ParametersWithPadding) params;
            else
                throw new IllegalArgumentException("CMac mode only permits parameters type of ParametersWithPadding.");
        }
    
        public int getMacSize() {
            return macSize;
        }
    
        public void update(byte in) {
            if (bufOff == buf.length) {
                cipher.processBlock(buf, 0, mac, 0);
                bufOff = 0;
            }
    
            buf[bufOff++] = in;
        }
    
        public void update(byte[] in, int inOff, int len) {
            if (len < 0) {
                throw new IllegalArgumentException("Can't have a negative input length!");
            }
    
            int blockSize = cipher.getBlockSize();
            int gapLen = blockSize - bufOff;
    
            if (len > gapLen) {
                System.arraycopy(in, inOff, buf, bufOff, gapLen);
    
                initTransform(parameters.transformInit); //4.初始变换
    
                bufOff = 0;
                len -= gapLen;
                inOff += gapLen;
    
                //5.迭代应用分组密码
                while (len > blockSize) {
                    cipher.processBlock(in, inOff, mac, 0);
                    len -= blockSize;
                    inOff += blockSize;
                }
            }
    
            System.arraycopy(in, inOff, buf, bufOff, len);
            bufOff += len;
        }
    
        public int doFinal(byte[] out, int outOff) {
            int msgLen = bufOff;
    
            paddingTransform(parameters.typePad); //2.消息填充。填充最后一个分组
            lastIteration(parameters.lastIteration, msgLen); //6.最终迭代
            outTransform(parameters.transformOut); //7.输出变换
            truncate(parameters.truncate, out, outOff, msgLen); //8.截断操作
    
            reset();
            return macSize;
        }
    
        /**
         * 密钥诱导。
         */
        void keyInduce() {
            KeyInduce keyInduce = new KeyInduce(cipher);
    
            if (parameters.typeAlg == 2) {
                //如果没有提供key2,则需要生成。
                //为了兼容2008,通过keyInduce参数决定密钥生成方式。0表示使用2008标准中的密钥诱导;1表示使用2020标准中的密钥诱导1。
                if (parameters.key2 == null) {
                    if(parameters.keyInduce==0)
                        parameters.key2 = keyInduce.induce0(parameters.key1);
                    else {
                        keyInduce.induce1(parameters.key1.length);
                        parameters.key1 = keyInduce.K1;
                        parameters.key2 = keyInduce.K2;
                    }
                }
            } else if (parameters.typeAlg == 4) {
                //需要生成初始变换2的密钥K1:如果提供了key2,则用2008标准中的密钥诱导生成K1;
                //如果没有提供key2,则需用密钥诱导1生成K1,以及要在输出变换2中使用的密钥key2
                if (parameters.key2 != null)
                    K1 = keyInduce.induce0(parameters.key2);
                else {
                    keyInduce.induce1(parameters.key1.length);
                    parameters.key2 = keyInduce.K1;
                    K1 = keyInduce.K2;
                }
            } else if (parameters.typeAlg == 5) {
                //最终迭代3中的两个密钥用密钥诱导2生成;分别放在K1和K2中
                keyInduce.induce2();
                K1 = keyInduce.K1;
                K2 = keyInduce.K2;
            } else if (parameters.typeAlg == 6) {
                //当只提供一个密钥时,需用密钥诱导1生成所需的两个密钥。用于最终迭代2的密钥放在K2中
                if (parameters.key2 == null) {
                    keyInduce.induce1(parameters.key1.length);
                    parameters.key1 = keyInduce.K1;
                    K2 = keyInduce.K2; //用于最终迭代2,故不设置key2
                    cipher.init(true, parameters.getParameters()); //使用密钥诱导生成了key1,需要重新初始化cipher
                } else
                    K2 = parameters.key2;
            }
        }
    
        /**
         * 填充。
         *
         * @param type 填充方式
         */
        void paddingTransform(int type) {
            int blockSize = cipher.getBlockSize();
            if (type == 1 || type == 3) {
                if (bufOff != blockSize)
                    new ZeroBytePadding().addPadding(buf, bufOff);
            } else if (type == 2) {
                if (bufOff == blockSize) {
                    cipher.processBlock(buf, 0, mac, 0);
                    bufOff = 0;
                }
                new ISO7816d4Padding().addPadding(buf, bufOff);
            } else if (type == 4) {
                if (bufOff != blockSize)
                    new ISO7816d4Padding().addPadding(buf, bufOff);
            }
        }
    
        /**
         * 初始变换。
         *
         * @param type 初始变换方式
         */
        void initTransform(int type) {
            cipher.processBlock(buf, 0, mac, 0);
    
            if (type == 2) {
                //初始变换2:使用子密钥加密后再使用原密钥进行后续加密
                reset();
                cipher.init(true, new KeyParameter(K1));
                cipher.processBlock(mac, 0, mac, 0);
                cipher.init(true, new ParametersWithIV(parameters.getParameters(), mac));
            } else if (type == 3) {
                cipher.reset();
                byte[] zeroes = new byte[cipher.getBlockSize()];
                cipher.processBlock(zeroes, 0, mac, 0);
                xor(buf, mac);
                cipher.reset();
                cipher.processBlock(buf, 0, mac, 0);
            }
        }
    
        /**
         * 输出变换。
         *
         * @param type 输出变换方式
         */
        void outTransform(int type) {
            if (type == 2) {
                //使用子密钥再加密一次
                reset();
                //这里需要使用全0的IV进行初始化,因为在算法4的“初始化变换”中使用了非0的IV,如果只是reset,则IV不是全0,会导致结果有误
                cipher.init(true, new ParametersWithIV(new KeyParameter(parameters.key2), new byte[cipher.getBlockSize()]));
                cipher.processBlock(mac, 0, mac, 0);
            } else if (type == 3) {
                //使用子密钥解密后再使用原密钥加密
                cipher.init(false, new KeyParameter(parameters.key2));
                cipher.processBlock(mac, 0, mac, 0);
    
                reset();
                cipher.init(true, parameters.getParameters());
                cipher.processBlock(mac, 0, mac, 0);
            }
        }
    
    
        /**
         * 最终迭代。
         *
         * @param type   迭代类型
         * @param msgLen 最后的消息长度
         */
        void lastIteration(int type, int msgLen) {
            if (type == 1)
                cipher.processBlock(buf, 0, mac, 0);
            if (type == 2) {
                xor(mac, buf);
                reset();
                cipher.init(true, new ParametersWithIV(new KeyParameter(K2), new byte[cipher.getBlockSize()]));
                cipher.processBlock(mac, 0, mac, 0);
            } else if (type == 3) {
                if (msgLen % cipher.getBlockSize() == 0)
                    xor(buf, K1);
                else
                    xor(buf, K2);
                cipher.processBlock(buf, 0, mac, 0);
            } else if (type == 4) {
                byte[] temp = new byte[cipher.getBlockSize()];
                xor(mac, buf);
                if (msgLen % cipher.getBlockSize() == 0)
                    shiftRight(mac, temp);
                else
                    shiftLeft(mac, temp);
                System.arraycopy(temp, 0, mac, 0, temp.length);
    
                reset();
                cipher.init(true, parameters.getParameters());
                cipher.processBlock(mac, 0, mac, 0);
            }
        }
    
        /**
         * 截断操作。
         *
         * @param type   截断类型
         * @param out    输出缓冲
         * @param outOff 输出偏移
         * @param msgLen 最后的消息长度
         */
        void truncate(int type, byte[] out, int outOff, int msgLen) {
            if (type == 2 && msgLen % cipher.getBlockSize() != 0)
                System.arraycopy(mac, mac.length - macSize, out, outOff, macSize);
            else
                System.arraycopy(mac, 0, out, outOff, macSize);
        }
    
        public void reset() {
            //clean the buffer.
            Arrays.fill(buf, (byte) 0);
            bufOff = 0;
    
            //reset the underlying cipher.
            cipher.reset();
        }
    
    
        static void xor(byte[] a, byte[] b) {
            for (int i = 0; i < a.length; i++)
                a[i] ^= b[i];
        }
    
        /**
         * 循环左移。
         */
        private static int shiftLeft(byte[] input, byte[] output) {
            int i = input.length;
            int bit = 0;
            while (--i >= 0) {
                int b = input[i] & 0xff;
                output[i] = (byte) ((b << 1) | bit);
                bit = (b >>> 7) & 1;
            }
            return bit;
        }
    
        /**
         * 循环右移。
         */
        private static int shiftRight(byte[] input, byte[] output) {
            int i = 0;
            int bit = 0;
            while (i < input.length) {
                int b = input[i] & 0xff;
                output[i] = (byte) ((b >>> 1) | bit);
                bit = (b << 7) & 0x80;
                i++;
            }
    
            output[0] |= bit;
    
            return bit;
        }
    
        /**
         * 密钥诱导。
         */
        static class KeyInduce {
            final BlockCipher cipher;
            byte[] K1;
            byte[] K2;
    
            KeyInduce(BlockCipher blockCipher) {
                this.cipher = blockCipher;
            }
    
            /**
             * 密钥诱导1.
             *
             * @param keyLength 分组密钥密钥长度k
             */
            void induce1(int keyLength) {
                int t = keyLength / cipher.getBlockSize();
                K1 = genKey(0, t);
                cipher.reset();
                K2 = genKey(t, 2 * t);
            }
    
            /**
             * 密钥诱导2.
             */
            void induce2() {
                byte[] zeroes = new byte[cipher.getBlockSize()];
                byte[] L = new byte[zeroes.length];
                cipher.processBlock(zeroes, 0, L, 0);
                K1 = multx(L);
                K2 = multx(K1);
            }
    
            /**
             * 《GBT 15852.1-2008》密钥诱导。
             * 

    * 用在算法2和算法4中。 *

    * 过程:对K从第1个4比特组开始,每隔4比特交替取补和不变 * * @param key 密钥 * @return 子密钥 */ public byte[] induce0(byte[] key) { byte[] result = key.clone(); for (int i = 0; i < result.length; i++) result[i] = (byte) ((~result[i] & 0xF0) ^ (result[i] & 0x0F)); return result; } byte[] genKey(int start, int end) { int blockSize = cipher.getBlockSize(); int len = end - start; byte[] S = new byte[len * blockSize]; for (int i = start; i < end; i++) { byte[] ct = new byte[blockSize]; byte[] temp = Pack.intToBigEndian(i + 1); System.arraycopy(temp, 0, ct, ct.length - temp.length, temp.length); cipher.processBlock(ct, 0, S, (i - start) * blockSize); } return Arrays.copyOfRange(S, (len - 1) * blockSize, S.length); } /** * multx(CMac.doubleLu). * * @param in 比特串T * @see CMac */ byte[] multx(byte[] in) { byte[] ret = new byte[in.length]; int carry = shiftLeft(in, ret); byte[] poly = lookupPoly(cipher.getBlockSize()); int mask = (-carry) & 0xff; ret[in.length - 3] ^= poly[1] & mask; ret[in.length - 2] ^= poly[2] & mask; ret[in.length - 1] ^= poly[3] & mask; return ret; } /** * lookup. * * @see CMac */ static byte[] lookupPoly(int blockSizeLength) { int xor = 0; switch (blockSizeLength * 8) { case 64: xor = 0x1B; break; case 128: xor = 0x87; break; } return Pack.intToBigEndian(xor); } } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434

    密钥诱导

    在2008标准中定义了一个密钥诱导,在2020标准中定义了另外两个不同的密钥诱导,即密钥诱导1和密钥诱导2。密钥诱导在YCMac中的keyInduce方法中按照不同的算法进行处理。

    但对于算法2有点特殊,为了兼容2008标准及其附录测试,在ParametersWithPadding中定义了keyInduce参数表示密钥诱导方式(仅用于算法2中)。

    • 0表示使用2008标准中的密钥诱导;在2008标准中定义,并在附录测试中用到;
    • 1表示使用2020标准中的密钥诱导1。在2020标准中定义,但附录测试中提供了2个密钥,未用到。
      默认为1,以符合2020标准。所以为了兼容2008标准或验证2008标准的附录测试,需要手动设置为0.

    算法1/3/7/8不需要密钥诱导,其他算法的密钥诱导参看下面的代码:

    void keyInduce() {
            KeyInduce keyInduce = new KeyInduce(cipher);
    
            if (parameters.typeAlg == 2) {
                //如果没有提供key2,则需要生成。
                //为了兼容2008,通过keyInduce参数决定密钥生成方式。0表示使用2008标准中的密钥诱导;1表示使用2020标准中的密钥诱导1。
                if (parameters.key2 == null) {
                    if(parameters.keyInduce==0)
                        parameters.key2 = keyInduce.induce0(parameters.key1);
                    else {
                        keyInduce.induce1(parameters.key1.length);
                        parameters.key1 = keyInduce.K1;
                        parameters.key2 = keyInduce.K2;
                    }
                }
            } else if (parameters.typeAlg == 4) {
                //需要生成初始变换2的密钥K1:如果提供了key2,则用2008标准中的密钥诱导生成K1;
                //如果没有提供key2,则需用密钥诱导1生成K1,以及要在输出变换2中使用的密钥key2
                if (parameters.key2 != null)
                    K1 = keyInduce.induce0(parameters.key2);
                else {
                    keyInduce.induce1(parameters.key1.length);
                    parameters.key2 = keyInduce.K1;
                    K1 = keyInduce.K2;
                }
            } else if (parameters.typeAlg == 5) {
                //最终迭代3中的两个密钥用密钥诱导2生成;分别放在K1和K2中
                keyInduce.induce2();
                K1 = keyInduce.K1;
                K2 = keyInduce.K2;
            } else if (parameters.typeAlg == 6) {
                //当只提供一个密钥时,需用密钥诱导1生成所需的两个密钥。用于最终迭代2的密钥放在K2中
                if (parameters.key2 == null) {
                    keyInduce.induce1(parameters.key1.length);
                    parameters.key1 = keyInduce.K1;
                    K2 = keyInduce.K2; //用于最终迭代2,故不设置key2
                    cipher.init(true, parameters.getParameters()); //使用密钥诱导生成了key1,需要重新初始化cipher
                } else
                    K2 = parameters.key2;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    测试

    在YMacTest的 test_GBT15852_2020() 里对《GBT 15852.1-2020 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》-附录B 进行了测试和验证。

    CMAC测试: 《GBT 15852.1-2020 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》-附录B
    
    消息1:This is the test message for mac
    Hex: 54686973206973207468652074657374206d65737361676520666f72206d6163
    填充方式1:
    D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D2 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63 
    
    填充方式2:
    D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D2 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63 
    D3 | 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    
    填充方式3:
    D1 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 
    D2 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D3 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63 
    
    
    填充方式4:
    D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D2 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63 
    
    
    消息2:This is the test message 
    hex: 54686973206973207468652074657374206d65737361676520
    填充方式1:
    D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D2 | 20 6D 65 73 73 61 67 65 20 00 00 00 00 00 00 00 
    
    填充方式2:
    D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D2 | 20 6D 65 73 73 61 67 65 20 80 00 00 00 00 00 00 
    
    填充方式3:
    D1 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C8 
    D2 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D3 | 20 6D 65 73 73 61 67 65 20 00 00 00 00 00 00 00 
    
    
    填充方式4:
    D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74 
    D2 | 20 6D 65 73 73 61 67 65 20 80 00 00 00 00 00 00 
    
    
    
    mac算法测试:
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法1: 
    填充方法1: 
    MAC= 16 E0 29 04 EF B7 65 B7 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法1: 
    填充方法2: 
    MAC= 4B 65 53 AF 3C 4E 27 44 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法1: 
    填充方法3: 
    MAC= 71 AF 7E 45 53 40 4C BC 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法1: 
    填充方法1: 
    MAC= BA 89 E4 5F E8 AB F2 42 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法1: 
    填充方法2: 
    MAC= 42 1A D1 69 0A A1 52 E2 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法1: 
    填充方法3: 
    MAC= 6A 4A 86 F5 B5 E4 68 DA 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法2: 
    填充方法1: 
    MAC= 1E 9A 71 D3 BC 92 DF A7 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法2: 
    填充方法2: 
    MAC= E4 23 E3 55 99 AF D9 48 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法2: 
    填充方法3: 
    MAC= 40 03 BA 1B 6A DC 53 A8 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法2: 
    填充方法1: 
    MAC= 4E C3 C7 FA CF AA C6 07 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法2: 
    填充方法2: 
    MAC= F0 26 25 CE AD 00 8D 4E 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法2: 
    填充方法3: 
    MAC= FF D5 F1 F2 E5 ED A5 CB 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法3: 
    填充方法1: 
    MAC= 27 63 21 1B 2B CA F7 19 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法3: 
    填充方法2: 
    MAC= 51 E9 92 8C 22 38 33 0C 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法3: 
    填充方法3: 
    MAC= 7C D4 8C 42 42 E4 55 75 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法3: 
    填充方法1: 
    MAC= E3 2D 99 A6 89 C0 52 59 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法3: 
    填充方法2: 
    MAC= 19 72 47 22 9C E9 D7 B6 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法3: 
    填充方法3: 
    MAC= 3C 43 0F 1E A4 3B 54 0C 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法4: 
    填充方法1: 
    MAC= DD 10 52 A7 AF E8 99 9B 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法4: 
    填充方法2: 
    MAC= 7E 1A 9A 5E 0E F0 94 7F 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法4: 
    填充方法3: 
    MAC= 28 A7 0D 6B CC F7 44 22 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法4: 
    填充方法1: 
    MAC= AA 9D B3 D9 65 1F 86 2B 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法4: 
    填充方法2: 
    MAC= 94 94 76 D3 5F 17 26 1E 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法4: 
    填充方法3: 
    MAC= C9 D3 4E 16 C4 9A B6 43 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法5: 
    填充方法4: 
    MAC= 69 2C 43 71 00 F3 B5 EE 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法5: 
    填充方法4: 
    MAC= 47 38 A6 C7 60 B2 80 FC 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法6: 
    填充方法1: 
    MAC= B3 8A 96 19 5B AA 61 FC 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法6: 
    填充方法2: 
    MAC= A0 C4 65 EE 58 96 97 2F 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法6: 
    填充方法3: 
    MAC= 43 05 0D 51 C6 56 AE 60 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法6: 
    填充方法1: 
    MAC= 8C F6 E6 43 14 FE F4 17 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法6: 
    填充方法2: 
    MAC= 60 DD 95 5E D0 CA 3D 7A 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法6: 
    填充方法3: 
    MAC= 61 E0 00 49 E2 69 62 A3 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法7: 
    填充方法4: 
    MAC= 16 E0 29 04 EF B7 65 B7 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法7: 
    填充方法4: 
    MAC= 84 6F A2 A5 D8 34 45 A9 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
    MAC算法8: 
    填充方法4: 
    MAC= E4 0E D7 9C 31 49 A1 C9 
    
    --------------------------------------------------
    消息: 54686973206973207468652074657374206d65737361676520
    MAC算法8: 
    填充方法4: 
    MAC= A9 9D 13 01 3E 89 2E E2 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263

    以下是2008标准的相关内容,现可忽略。

    CMAC:《GBT 15852.1-2008》

    1. 总结
    MAC算法(6种)数据填充(3种)初始变换(2种)输出变换(3种)输入密钥1输入密钥2生成诱导密钥
    算法1任选11××
    算法2任选12×
    算法3任选13×
    算法4任选22
    算法5任选
    算法6任选

    其中,算法5是两个算法1的MAC相异或;算法6是两个算法4的MAC相异或 。

    1. 实现
    • CMac14实现了算法 1-4 ,CMac56实现了算法5~6。
    • 算法参数放在ParametersWithPadding类中,包括算法类型,填充方式,密钥,向量,初始变换,输出变换。默认CMAC的向量为全0,添加了IV以支持其他向量值。
    • YCMac类中还提供了一个基于算法1,填充1的支持update模式的CMAC方法。
      在《GBT 36322》中有一个SDF_CalculateMAC接口,支持IV的输入输出,支持多包处理,可以用此方法来实现。
      其他的MAC算法实现不了,因为它们的输出变换用了另外的密钥来进行处理,所以不支持update模式。
    1. 代码示例
    /**
     * 《GBT 15852.1-2008 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》算法1~4。
     *
     * @author YaoYuan
     * @since 2022/11/2
     */
    public class CMac14 implements Mac {
        private byte[] mac; //mac值
    
        private byte[] buf; //内部缓冲区
        private int bufOff; //缓冲区当前数据长度
        private BlockCipher cipher; //底层对称算法对象
    
        private int macSize; //所需的Mac大小
    
        private byte[] subKey; //子密钥
        ParametersWithPadding parameters; //算法参数
        private boolean needTransformInit = false; //是否需要初始变换
    
        public CMac14(BlockCipher cipher) {
            this(cipher, cipher.getBlockSize() * 8);
        }
    
        public CMac14(BlockCipher cipher, int macSizeInBits) {
            if ((macSizeInBits % 8) != 0) {
                throw new IllegalArgumentException("MAC size must be multiple of 8");
            }
    
            if (macSizeInBits > (cipher.getBlockSize() * 8)) {
                throw new IllegalArgumentException("MAC size must be less or equal to "+ (cipher.getBlockSize() * 8));
            }
    
            this.cipher = new CBCBlockCipher(cipher);
            this.macSize = macSizeInBits / 8;
    
            mac = new byte[cipher.getBlockSize()];
            buf = new byte[cipher.getBlockSize()];
            bufOff = 0;
        }
    
        public String getAlgorithmName() {
            return cipher.getAlgorithmName();
        }
    
        public void init(CipherParameters params) {
            validate(params);
    
            cipher.init(true, parameters.getParameters());
    
            //设置子密钥
            if (parameters.typeAlg == 2)
                subKey = YCMac.genKey(parameters.key1);
            else if (parameters.typeAlg == 3)
                subKey = parameters.key2.clone();
            else if (parameters.typeAlg == 4)
                subKey = YCMac.genKey(parameters.key2);
    
            //只有在初始变换2中才需要额外的初始变换操作
            if (parameters.transformInit == 2)
                needTransformInit = true;
    
            reset();
    
            //填充方式3:处理在开头添加的填充块
            if (parameters.typePad == 3) {
                byte[] temp = new byte[cipher.getBlockSize()];
                byte[] bLen = Pack.intToBigEndian(parameters.length * 8);
                System.arraycopy(bLen, 0, temp, temp.length - bLen.length, bLen.length);
                update(temp, 0, temp.length);
            }
        }
    
        void validate(CipherParameters params) {
            if (params instanceof ParametersWithPadding)
                parameters = (ParametersWithPadding) params;
            else
                throw new IllegalArgumentException("CMac mode only permits parameters type of ParametersWithPadding.");
        }
    
        public int getMacSize() {
            return macSize;
        }
    
        public void update(byte in) {
            if (bufOff == buf.length) {
                cipher.processBlock(buf, 0, mac, 0);
                bufOff = 0;
            }
    
            buf[bufOff++] = in;
        }
    
        public void update(byte[] in, int inOff, int len) {
            if (len < 0) {
                throw new IllegalArgumentException("Can't have a negative input length!");
            }
    
            int blockSize = cipher.getBlockSize();
            int gapLen = blockSize - bufOff;
    
            if (len > gapLen) {
                System.arraycopy(in, inOff, buf, bufOff, gapLen);
    
                cipher.processBlock(buf, 0, mac, 0);
                //初始变换
                if (needTransformInit) {
                    needTransformInit = false;
                    initTransform(parameters.transformInit);
                    //重设算法4的密钥
                    if (parameters.typeAlg == 4)
                        subKey = parameters.key2.clone();
                }
    
                bufOff = 0;
                len -= gapLen;
                inOff += gapLen;
    
                while (len > blockSize) {
                    cipher.processBlock(in, inOff, mac, 0);
                    len -= blockSize;
                    inOff += blockSize;
                }
            }
    
            System.arraycopy(in, inOff, buf, bufOff, len);
            bufOff += len;
        }
    
        public int doFinal(byte[] out, int outOff) {
            //最后一个分组的填充
            paddingTransform(parameters.typePad);
            cipher.processBlock(buf, 0, mac, 0);
            //输出变换
            outTransform(parameters.transformOut);
    
            System.arraycopy(mac, 0, out, outOff, macSize);
            reset();
            return macSize;
        }
    
        /**
         * 填充。
         *
         * @param type 填充方式
         */
        void paddingTransform(int type) {
            int blockSize = cipher.getBlockSize();
            if (type == 1 || type == 3) {
                if (bufOff != blockSize)
                    new ZeroBytePadding().addPadding(buf, bufOff);
            } else {
                if (bufOff == blockSize) {
                    cipher.processBlock(buf, 0, mac, 0);
                    bufOff = 0;
                }
                new ISO7816d4Padding().addPadding(buf, bufOff);
            }
        }
    
        /**
         * 初始变换。
         *
         * @param type 变换方式
         */
        void initTransform(int type) {
            //只有初始变换2才需要处理:使用子密钥加密后再使用原密钥进行后续加密
            if (type == 2) {
                reset();
                cipher.init(true, new KeyParameter(subKey));
                cipher.processBlock(mac, 0, mac, 0);
                cipher.init(true, new ParametersWithIV(parameters.getParameters(), mac));
            }
        }
    
        /**
         * 输出变换。
         *
         * @param type 变换方式
         */
        void outTransform(int type) {
            if (type == 2) {
                //使用子密钥再加密一次
                reset();
                //这里需要使用全0的IV进行初始化,因为在算法4的“初始化变换”中使用了非0的IV,如果只是reset,则IV不是全0,会导致结果有误
                cipher.init(true, new ParametersWithIV(new KeyParameter(subKey), new byte[cipher.getBlockSize()]));
                cipher.processBlock(mac, 0, mac, 0);
            } else if (type == 3) {
                //先解密再加密
                cipher.init(false, new KeyParameter(subKey));
                cipher.processBlock(mac, 0, mac, 0);
    
                reset();
                cipher.init(true, parameters.getParameters());
                cipher.processBlock(mac, 0, mac, 0);
            }
        }
    
        public void reset() {
            //clean the buffer.
            Arrays.fill(buf, (byte) 0);
            bufOff = 0;
    
            //reset the underlying cipher.
            cipher.reset();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206

    测试

    在例子中测试了:

    • 《GBT 15852.1》附录A 测试和验证
    • SP800-38B测试和验证:其中的TDEA中有两个Mac值验证失败,应该是文档本身的错误。
    • CMac-update-iv的测试和验证

    IDEA中的测试输出:

    1. GBT 15852.1:
    CMAC测试: 《GBT 15852.1-2008 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》-附录A
    
    消息1:Now is the time for all 
    Hex: 4e6f77206973207468652074696d6520666f7220616c6c20
    填充方式1:
    D1 | 4E 6F 77 20 69 73 20 74 
    D2 | 68 65 20 74 69 6D 65 20 
    D3 | 66 6F 72 20 61 6C 6C 20 
    
    填充方式2:
    D1 | 4E 6F 77 20 69 73 20 74 
    D2 | 68 65 20 74 69 6D 65 20 
    D3 | 66 6F 72 20 61 6C 6C 20 
    D4 | 80 00 00 00 00 00 00 00 
    
    填充方式3:
    D1 | 00 00 00 00 00 00 00 C0 
    D2 | 4E 6F 77 20 69 73 20 74 
    D3 | 68 65 20 74 69 6D 65 20 
    D4 | 66 6F 72 20 61 6C 6C 20 
    
    
    消息2:Now is the time for it
    hex: 4e6f77206973207468652074696d6520666f72206974
    填充方式1:
    D1 | 4E 6F 77 20 69 73 20 74 
    D2 | 68 65 20 74 69 6D 65 20 
    D3 | 66 6F 72 20 69 74 00 00 
    
    填充方式2:
    D1 | 4E 6F 77 20 69 73 20 74 
    D2 | 68 65 20 74 69 6D 65 20 
    D3 | 66 6F 72 20 69 74 80 00 
    
    填充方式3:
    D1 | 00 00 00 00 00 00 00 B0 
    D2 | 4E 6F 77 20 69 73 20 74 
    D3 | 68 65 20 74 69 6D 65 20 
    D4 | 66 6F 72 20 69 74 00 00 
    
    
    mac算法测试:
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法1: 
    填充方法1: 
    MAC= 70 A3 06 40 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法1: 
    填充方法2: 
    MAC= 10 E1 F0 F1 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法1: 
    填充方法3: 
    MAC= 2C 58 FB 8F 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法1: 
    填充方法1: 
    MAC= E4 5B 3A D2 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法1: 
    填充方法2: 
    MAC= A9 24 C7 21 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法1: 
    填充方法3: 
    MAC= B1 EC D6 FC 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法2: 
    填充方法1: 
    MAC= 10 F9 BC 67 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法2: 
    填充方法2: 
    MAC= BE 7C 2A B7 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法2: 
    填充方法3: 
    MAC= 8E FC 8B C7 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法2: 
    填充方法1: 
    MAC= 21 5E 9C E6 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法2: 
    填充方法2: 
    MAC= 17 36 AC 1A 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法2: 
    填充方法3: 
    MAC= 05 38 26 96 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法3: 
    填充方法1: 
    MAC= A1 C7 2E 74 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法3: 
    填充方法2: 
    MAC= E9 08 62 30 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法3: 
    填充方法3: 
    MAC= AB 05 94 63 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法3: 
    填充方法1: 
    MAC= 2E 2B 14 28 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法3: 
    填充方法2: 
    MAC= 5A 69 2C E6 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法3: 
    填充方法3: 
    MAC= C5 9F 7E ED 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法4: 
    填充方法1: 
    MAC= AD 35 02 B7 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法4: 
    填充方法2: 
    MAC= 61 C3 33 E3 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法4: 
    填充方法3: 
    MAC= 95 2A F8 38 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法4: 
    填充方法1: 
    MAC= 05 F1 08 4C 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法4: 
    填充方法2: 
    MAC= A1 BC 09 31 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法4: 
    填充方法3: 
    MAC= AF DE E0 F9 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法5: 
    填充方法1: 
    MAC= F4 E4 02 B6 B7 2C 13 17 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法5: 
    填充方法2: 
    MAC= 70 F0 5E C9 E4 F7 2F 99 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法5: 
    填充方法3: 
    MAC= D6 1F 51 F2 EA 2A 2D 63 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法5: 
    填充方法1: 
    MAC= 0F 24 BD A4 AC 22 0F 4F 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法5: 
    填充方法2: 
    MAC= E0 04 13 41 9A FC 16 0B 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法5: 
    填充方法3: 
    MAC= DD DF 5E D3 0F 18 EB FC 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法6: 
    填充方法1: 
    MAC= 57 7E F2 21 18 CE 5D BA 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法6: 
    填充方法2: 
    MAC= 60 74 60 B8 D8 C0 FD FA 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f7220616c6c20
    MAC算法6: 
    填充方法3: 
    MAC= FD 3D BB 6E F1 65 07 54 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法6: 
    填充方法1: 
    MAC= 10 F7 47 D1 4F 72 C2 29 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法6: 
    填充方法2: 
    MAC= B2 9B 9A 76 DD 1C 39 12 
    
    --------------------------------------------------
    消息: 4e6f77206973207468652074696d6520666f72206974
    MAC算法6: 
    填充方法3: 
    MAC= F6 45 FB 7D 4D 4A 42 B4 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    1. SP800-3B
    com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 org.yy.mac.YMacTest,test_omac1
    omac SP800-38B verify: 
    ====================================================================
    algorithm : AES128
    key: 2b7e151628aed2a6abf7158809cf4f3c
    msg: 
    mac: bb1d6929e95937287fa37d129b756746
    ====================================================================
    algorithm : AES128
    key: 2b7e151628aed2a6abf7158809cf4f3c
    msg: 6bc1bee22e409f96e93d7e117393172a
    mac: 070a16b46b4d4144f79bdd9dd04a287c
    ====================================================================
    algorithm : AES128
    key: 2b7e151628aed2a6abf7158809cf4f3c
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411
    mac: dfa66747de9ae63030ca32611497c827
    ====================================================================
    algorithm : AES128
    key: 2b7e151628aed2a6abf7158809cf4f3c
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
    mac: 51f0bebf7e3b9d92fc49741779363cfe
    ====================================================================
    algorithm : AES192
    key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
    msg: 
    mac: d17ddf46adaacde531cac483de7a9367
    ====================================================================
    algorithm : AES192
    key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
    msg: 6bc1bee22e409f96e93d7e117393172a
    mac: 9e99a7bf31e710900662f65e617c5184
    ====================================================================
    algorithm : AES192
    key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411
    mac: 8a1de5be2eb31aad089a82e6ee908b0e
    ====================================================================
    algorithm : AES192
    key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
    mac: a1d5df0eed790f794d77589659f39a11
    ====================================================================
    algorithm : AES256
    key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
    msg: 
    mac: 028962f61b7bf89efc6b551f4667d983
    ====================================================================
    algorithm : AES256
    key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
    msg: 6bc1bee22e409f96e93d7e117393172a
    mac: 28a7023f452e8f82bd4bf28d8c37c35c
    ====================================================================
    algorithm : AES256
    key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411
    mac: aaf3d8f1de5640c232f5b169b9c911e6
    ====================================================================
    algorithm : AES256
    key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
    mac: e1992190549f6ed5696a2c056c315410
    ====================================================================
    algorithm : DESede3
    key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
    msg: 
    mac: b7a688e122ffaf95
    ====================================================================
    algorithm : DESede3
    key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
    msg: 6bc1bee22e409f96
    mac: 8e8f293136283797
    ====================================================================
    algorithm : DESede3
    key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a57
    mac: 743ddbe0ce2dc2ed
    ====================================================================
    algorithm : DESede3
    key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
    mac: 33e6b1092400eae5
    ====================================================================
    algorithm : DESede
    key: 4cf15134a2850dd58a3d10ba80570d38
    msg: 
    mac: bd2ebf9a3ba00361
    ====================================================================
    algorithm : DESede
    key: 4cf15134a2850dd58a3d10ba80570d38
    msg: 6bc1bee22e409f96
    mac: 4ff2ab813c53ce83
    ====================================================================
    algorithm : DESede
    key: 4cf15134a2850dd58a3d10ba80570d38
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a57
    mac: 62dd1b471902bd4e
    ====================================================================
    algorithm : DESede
    key: 4cf15134a2850dd58a3d10ba80570d38
    msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
    mac: 31b1e431dabc4eb8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
  • 相关阅读:
    【Autopsy数字取证篇】Autopsy案例更改时区
    数据传输的加密解密
    前端表单滑块验证码开发
    SpringBoot发送请求与匹配响应信息
    SSL/TLS工作原理:密钥、证书、SSL握手
    css定位详解
    杀掉进程但是fastapi程序还在运行
    必须要会回答的Java面试题(字符串篇)
    springboot整合
    如何理解Python中一切皆对象?
  • 原文地址:https://blog.csdn.net/yaoyuanyylyy/article/details/127687829