java - 如何在java密码学中将位插入块中?

2022-01-10 00:00:00 encryption cryptography java

我正在尝试制作一个涉及密码学的简单 Java 程序.

I am trying to make a simple Java program that involves cryptography.

首先,我从文件 clearmsg.txt 中读取一个 32 字节的块.然后我将此块转换为整数,并将其用于加密.不幸的是,密文的大小不是静态的;有时它返回 30 个字节,有时返回 26 个字节.这似乎与添加操作的结果无关.

First I read a block of 32 bytes from file clearmsg.txt. Then I convert this block to integer number, and use it for encryption. Unfortunately the size of the ciphertext is not static; sometimes it returns 30 bytes and sometimes 26 bytes. This seems independent on result of add operation.

如何确保它变成 32 字节的密码块?如何向这个块添加位/字节?因为当我尝试解密这个块时,我需要读取 32 个密文字节.

How can I make sure it becomes a cipher block of 32 bytes? How add bits / bytes to this block? Because when I try decrypt this block I need to read 32 ciphertext bytes.

private void ENC_add() {

    final File clearmsg = new File("F:/java_projects/clearmsg.txt");
    final File ciphermsg = new File("F:/java_projects/ciphermsg.txt");
    final byte[] block = new byte[32];
    try {
        final FileInputStream fis = new FileInputStream(clearmsg);
        final FileOutputStream fcs = new FileOutputStream(ciphermsg);
        int i;
        while ((i = fis.read(block)) != -1) {
            // Is this process true
            // here M2 (Plain text) shuld be 32 byte
            M2 = new BigInteger(block);
            // here encrypt M2 by add k1 where k1 any number less than P
            CM2 = M2.add(K1).mod(P);
            // here my problem some time Cipher CM2 length 31 , some time CM2 length 32 ,some time CM2 length 30
            System.out.println("THE CM2=" + CM2.toByteArray().Length);
            fcs.write(CM2.toByteArray(), 0, i);
        }
        fcs.close();

    }

    catch (final IOException e) {
        e.printStackTrace();
    }
}

// Here problem for decrypt
private void DEC_ADD() {

    // DECREPT METHOD
    final File ciphermsg = new File("F:/java_projects/ciphermsg.txt");
    final File clearmsg = new File("F:/java_projects/rciphermsg.txt");
    final byte[] block = new byte[32];
    try {
        final FileInputStream fis = new FileInputStream(ciphermsg);
        final FileOutputStream fos = new FileOutputStream(clearmsg);
        int i;
        while ((i = fis.read(block)) != -1) {
            // CM2 NOT STATIC BITS NUMBER BECAUSE INDEPENDET ON RESULT ADDITIONAL AND PRIME NUMBER P through ENCRYPT
            // Process
            CM2 = new BigInteger(block);
            // here RM2 is decrypt cipher (CM2) NOTE When encrypt above M2 WAS 32 bytes and Cipher CM2 was 30 bytes
            // and When I read from file 32 bytes then this is my problem
            RM2 = CM2.subtract(K1).mod(P);

            fos.write(RM2.toByteArray(), 0, i);
        }
        fos.close();
        System.out.println("THE RM2=" + CM2.bitLength());
    } catch (final IOException e) {
        e.printStackTrace();
    }
}

推荐答案

对于加密,需要一个通常称为 Integer to Octet String Primitive 或 I2OSP 的函数.对于解密,您需要一个 OS2IP 函数来转换回整数.我在密码学姊妹网站上的回答中解释了两者.它们是 RSA PKCS#1 规范的一部分,在此处指定了 2.2 版.

For the encrypt a function is required that is normally called Integer to Octet String Primitive or I2OSP. For decryption you need an OS2IP function to convert back to integers. Both are explained in my answer on the cryptography sister site. They are part of the RSA PKCS#1 specifications, for which version 2.2 is specified here.

I2OSP 和 OS2IP 函数也用于其他加密原语.例如,它们可用于椭圆曲线密码学以创建平面 ECDSA 签名或 EC 公钥表示.

The I2OSP and OS2IP functions are also used for other cryptographic primitives. For instance, they can be used for Elliptic Curve Cryptography to create flat ECDSA signatures or EC public key representations.

这些函数用于对给定大小的八位字节字符串(字节数组)进行编码/解码.此大小通常与 RSA 加密的模数(在您的情况下为 P)的大小直接相关.

These functions are used to encode/decode to an octet string (byte array) of a given size. This size is normally directly related to the size of the modulus (P in your case) of RSA encryption.

I2OSP 函数应该这样编码:

The I2OSP function should be coded like this:

public static byte[] i2osp(final BigInteger i, final int size) {
    if (size < 1) {
        throw new IllegalArgumentException("Size of the octet string should be at least 1 but is " + size);
    }

    if (i == null || i.signum() == -1 || i.bitLength() > size * Byte.SIZE) {
        throw new IllegalArgumentException("Integer should be a positive number or 0, no larger than the given size");
    }

    final byte[] signed = i.toByteArray();
    if (signed.length == size) {
        // (we are lucky, already the right size)
        return signed;
    }

    final byte[] os = new byte[size];
    if (signed.length < size) {
        // (the dynamically sized array is too small, pad with 00 valued bytes at the left)
        System.arraycopy(signed, 0, os, size - signed.length, signed.length);
        return os;
    }

    // (signed representation too large, remove leading 00 valued byte)
    System.arraycopy(signed, 1, os, 0, size);
    return os;
}

当然,要使用正确的大小八位字节/字节,您首先应该知道密钥大小(以字节为单位).对于 RSA 公钥或私钥,这可以很容易地从模数中计算出来(如果它不直接可用,如在 Java JCA 中):

Of course, to use this with the correct size in octets / bytes you should first know the key size in bytes first. For an RSA public- or private key this can be easily calculated from the modulus (in case it is not directly available, as in the Java JCA):

public static int keySizeInOctets(RSAKey key) {
    int keySizeBits = key.getModulus().bitLength();
    int keySizeBytes = (keySizeBits + Byte.SIZE - 1) / Byte.SIZE;
    return keySizeBytes;
}

请注意,RSAPublicKeyRSAPrivateKeyRSAPrivateCrtKey 都扩展了 RSAKey,后者提供了对模数的访问.因此,您可以直接使用这些类的实例作为此方法的参数.当然,Java 中的 RSA 提供程序在 CipherSignature 实现类中已经包含了 I2OSP 和 OS2IP,但是从位大小到字节大小的转换(没有浮点计算)可以派上用场.

Note that RSAPublicKey, RSAPrivateKey and RSAPrivateCrtKey all extend RSAKey which provides access to the modulus. So you can use instances of these classes directly as argument for this method. Of course, the RSA providers in Java already contain I2OSP and OS2IP within the Cipher and Signature implementation classes, but the conversion from bit size to byte size (without floating point calculations) could come in handy.

还好反转功能没那么复杂:

Fortunately, the reverse function is not as complicated:

public static BigInteger os2ip(final byte[] data, final int size) {
    if (data.length != size) {
        throw new IllegalArgumentException("Size of the octet string should be precisely " + size);
    }

    return new BigInteger(1, data); 
}

我保留了大小验证,因此可以使用 预期八位字节大小调用它,即使计算本身不需要它.

I've kept in the size validation so it can be called with the expected octet size, even though it is not required for the calculation itself.

相关文章