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

com.github.isaichkindanila.crypt.lib.cipher.ChaCha Maven / Gradle / Ivy

The newest version!
package com.github.isaichkindanila.crypt.lib.cipher;

import com.github.isaichkindanila.crypt.lib.util.ConversionUtils;

/*
 Reference:
    1. https://cr.yp.to/snuffle/salsafamily-20071225.pdf
    2. https://cr.yp.to/chacha/chacha-20080128.pdf
*/
class ChaCha extends StreamCipher {
    /*
        con con con con  |   0  1  2  3
        key key key key  |   4  5  6  7
        key key key key  |   8  9 10 11
        ctr ctr  iv  iv  |  12 13 14 15
     */
    private final int[] input = new int[16];
    private final int[] hashed = new int[16];
    private final byte[] block = new byte[64];
    private final int roundCount;
    private int initialCtr12Value;

    ChaCha(int roundCount) {
        this.roundCount = roundCount;
    }

    @Override
    protected void init0(byte[] key, byte[] iv) {
        input[0] = 0x61707865;
        input[1] = 0x3320646e;
        input[2] = 0x79622d32;
        input[3] = 0x6b206574;

        for (int i = 0; i < 8; i++) {
            input[i + 4] = ConversionUtils.bytesToInt(key, i * 4);
        }

        for (int i = 0; i < 4; i++) {
            input[i + 12] = ConversionUtils.bytesToInt(iv, i * 4);
        }

        initialCtr12Value = input[12];
    }

    private void quarterRound(int a, int b, int c, int d) {
        hashed[a] += hashed[b];
        hashed[d] ^= hashed[a];
        hashed[d] = Integer.rotateLeft(hashed[d], 16);

        hashed[c] += hashed[d];
        hashed[b] ^= hashed[c];
        hashed[b] = Integer.rotateLeft(hashed[b], 12);

        hashed[a] += hashed[b];
        hashed[d] ^= hashed[a];
        hashed[d] = Integer.rotateLeft(hashed[d], 8);

        hashed[c] += hashed[d];
        hashed[b] ^= hashed[c];
        hashed[d] = Integer.rotateLeft(hashed[b], 7);
    }

    @Override
    protected byte[] nextBlock() {
        // increase counter by 1
        if (++input[12] == initialCtr12Value) {
            input[13]++;
        }

        // initialize hashed array
        System.arraycopy(input, 0, hashed, 0, 16);

        // modify hashed array
        for (int i = 0; i < roundCount; i++) {
            quarterRound(0, 4, 8, 12);  // 1st column
            quarterRound(1, 5, 9, 13);  // 2nd column
            quarterRound(2, 6, 10, 14); // 3rd column
            quarterRound(3, 7, 11, 15); // 4th column

            quarterRound(0, 5, 10, 15); // 1st diagonal (main diagonal)
            quarterRound(1, 6, 11, 12); // 2nd diagonal ("above" 1st)
            quarterRound(2, 7, 8, 13);  // 3rd diagonal ("above" 2nd)
            quarterRound(3, 4, 9, 14);  // 4th diagonal ("above" 3rd)
        }

        // add input array to hashed array
        for (int i = 0; i < 16; i++) {
            hashed[i] += input[i];
        }

        // extract hashed array to block output
        for (int i = 0; i < 16; i++) {
            System.arraycopy(ConversionUtils.intToBytes(hashed[i]), 0, block, i * 4, 4);
        }

        return block;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy