3

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

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

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

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();
    }
}
4

1 回答 1

4

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

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

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

I2OSP 函数应该这样编码:

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 中):

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

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


幸运的是,反向函数没有那么复杂:

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); 
}

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

于 2013-09-16T09:33:12.693 回答