All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.siisise.security.mac.CMAC Maven / Gradle / Ivy

/*
 * Copyright 2022 Siisise Net.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.siisise.security.mac;

import net.siisise.io.Packet;
import net.siisise.io.PacketA;
import net.siisise.lang.Bin;
import net.siisise.math.GF;
import net.siisise.security.block.AES;
import net.siisise.security.block.Block;

/**
 * Cipher-based Message Authentication Code (CMAC).
 * 
 * OMAC は OMAC1 と OMAC2 の総称
 * OMAC1 は CMAC と同じ、これはCMAC
 * http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
 * 
 * GFなどで128bit または64bit 固定なのかも.
 * 
 * One-Key CBC MAC1 (OMAC1) と同じ
 * 
 * CBC-MAC の更新
 * XCBC / OMAC / CMAC = OMAC1 / TMAC
 * 
 * Tetsu Iwata, Kaoru Kurosawa、OMAC: One-Key CBC MAC、2003年、Fast Software Encryption, FSE 2003, LNCS 2887, pp. 129-153, Springer.
 * 
 * RFC 4493 The AES-CMAC Algorithm.
 * NIST SP 800-38B Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication.
 */
public class CMAC implements MAC {

    private final Block block; // E
    private MacCBC cbc;

    byte[] k1; // L・2 最後のブロックがブロック長と等しい場合
    byte[] k2; // k1・2 最後のブロックがブロック長より短い場合
    private long len;
    private Packet m;

    /**
     * AES-CMAC.
     */
    public CMAC() {
        this(new AES());
    }

    /**
     * AES-CMAC
     * @param key AES key 128bit
     */
    public CMAC(byte[] key) {
        this(new AES());
        init(key);
    }

    /**
     * 特定のブロック暗号のCMACっぽいものにする?
     * XXX-CMAC
     * 別途init必要
     * @param e ブロック暗号 E 
     */
    public CMAC(Block e) {
        block = e;
    }

    /**
     * RFC 4493 Section 2.3. Subkey Generation Algorithm
     * @param key AES鍵 AES-128 128bit AES-192 AES-256 でもいいかも
     */
    @Override
    public void init(byte[] key) {
        // Generate_Subkey
        block.init(key);
        int blen = getMacLength();
        byte[] L = block.encrypt(new byte[blen]);
        // RFC 4493にガロア体の説明はないが、実体はガロア体 OMAC1a に説明がある?
        GF gf;
        if (blen == 16) { // AES 128bit
            gf = new GF(blen*8,GF.FF128); // 0x87
        } else { // TDEA TripleDES 64bit 8bitも同じ
            gf = new GF(blen*8,GF.FF64 ); // 0x1b
        }
        initk(L,gf);
        // Generate_Subkey ここまで
        m = new PacketA();
        len = 0;
        // Step 5.
        cbc = new MacCBC(block);
    }

    /**
     * OMAC1 と OMAC2で違いそうなところ
     * @param L
     * @param gf 
     */
    void initk(byte[] L, GF gf) {
        k1 = gf.x(L);
        k2 = gf.x(k1);
    }

    @Override
    public void update(byte[] src, int offset, int length) {
        len += length;
        int ml = m.size();
        int last = offset + length;
        // Strp 6. A
        if ( ml > 0 && ml + length > k1.length ) {
            int wlen = k1.length - ml;
            m.write(src,offset,wlen);
            offset += wlen;
            cbc.update(m.toByteArray(), 0, k1.length);
        }
        while ( offset + k1.length < last ) {
            cbc.update(src,offset,k1.length);
            offset += k1.length;
        }
        m.write(src, offset, last - offset);
    }

    @Override
    public byte[] sign() {
        // Step 3. Step 4.
        byte[] T;
        if ( (len == 0) || ( len % k1.length != 0 ) ) { // padding(M)
            m.write(0x80);
            m.write(new byte[k2.length - m.size()]);
            T = m.toByteArray();
            Bin.xorl(T, k2);
        } else {
            T = m.toByteArray();
            Bin.xorl(T, k1);
        }
        cbc.update(T,0,T.length);
        T = cbc.vector();
        // Step 6. B Step 7.
        // 次の初期化
        cbc = new MacCBC(block); // Blockのkeyはそのまま、CBCのIVだけ初期化したい
        len = 0;
        return T;
    }

    @Override
    public int getMacLength() {
        return (block.getBlockLength() + 7) / 8;
    }

    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy