Are there any way to set the signature size while making DER file using bouncycastle.
Now I am making cert file using org.bouncycastle.
The following is my code. It works fine, but I could not handle the signature length.
** for the SHA256WITHRSA signature algorithm, the length is static as 256 for 2048 RSA key, and 128 for 1024 RSA key.**
I want to make a cert with 2048 public key and 128 signature.
Security.addProvider(new BouncyCastleProvider());
KeyPair keyPair = createKeyPair();
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(new X500Name("CN=Issuer"), BigInteger.ONE, new GregorianCalendar().getTime(), new GregorianCalendar().getTime(), new X500Name("CN=Subject"), keyPair.getPublic());
JcaContentSignerBuilder signerBuiler = new JcaContentSignerBuilder("SHA256WITHRSA").setProvider(BouncyCastleProvider.PROVIDER_NAME);
ContentSigner contentSigner = signerBuiler.build(keyPair.getPrivate());
X509Certificate certificate = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certBuilder.build(contentSigner));
certificate.verify(keyPair.getPublic());
System.out.println( certificate);
As the following, it has 2048 public key, but the signature size is 128 byte. This is DER file what I wanna make.
The output of RSA operations is always the size of the RSA key used. 2048 bits is 256 bytes. It's impossible to get a 128-byte result using a 256-byte key.
Related
I am trying to learn how to sign messages using the RSA algorithm with SHA256 in Java. When I generated a 2048-bit KeyPair, I found that both the public and private key were 294 bytes. Here is my code for finding the size of the keys:
import java.security.*;
public class RSATesting
{
public static void main(String[] args) throws Exception
{
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, new SecureRandom());
KeyPair pair = generator.generateKeyPair();
byte[] publicKeyBytes=pair.getPublic().getEncoded();
System.out.println(publicKeyBytes.length);
byte[] privateKeyBytes=pair.getPublic().getEncoded();
System.out.println(privateKeyBytes.length);
}
}
Why are the keys not 256 bytes?
Thanks
RSA keys aren't like AES keys.
AES keys are some random bytes. RSA keys are numbers. The RSA modulus (N) defines the lenght.
Your key is 294 bytes long, because of getEncoded();. It returns a formatted key and not the real lenght.
I have used the below OpenSSL code to do an AES encryption which is decrypting successfully in the Tax website
openssl rand 48 > 48byterandomvalue.bin
hexdump /bare 48byterandomvalue.bin > 48byterandomvalue.txt
set /a counter=0
for /f "tokens=* delims= " %%i in (48byterandomvalue.txt) do (
set /a counter=!counter!+1
set var=%%i
if "!counter!"=="1" (set aes1=%%i)
if "!counter!"=="2" (set aes2=%%i)
if "!counter!"=="3" (set iv=%%i)
)
set result1=%aes1:~0,50%
set result1=%result1: =%
set result2=%aes2:~0,50%
set result2=%result2: =%
set aeskey=%result1%%result2%
set initvector=%iv:~0,50%
set initvector=%initvector: =%
openssl aes-256-cbc -e -in PAYLOAD.zip -out PAYLOAD -K %aeskey% -iv %initvector%
openssl rsautl -encrypt -certin -inkey test_public.cer -in
48byterandomvalue.bin -out 000000.00000.TA.840_Key
But I wanted to do the same this in Java as part of migration, so i used the javax.crypto and java.security libraries but the decryption is failing when I upload the file on the Tax website
//creating the random AES-256 secret key
SecureRandom srandom = new SecureRandom();
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey secretKey = keyGen.generateKey();
byte[] aesKeyb = secretKey.getEncoded();
//creating the initialization vector
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
byte[] encoded = Files.readAllBytes(Paths.get(filePath));
str = new String(encoded, StandardCharsets.US_ASCII);
//fetching the Public Key from certificate
FileInputStream fin = new FileInputStream("test_public.cer");
CertificateFactory f = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)f.generateCertificate(fin);
PublicKey pk = certificate.getPublicKey();
//encrypting the AES Key with Public Key
Cipher RSACipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
RSACipher.init(Cipher.ENCRYPT_MODE, pk);
byte[] RSAEncrypted = RSACipher.doFinal(aesKeyb);
FileOutputStream out = new FileOutputStream("000000.00000.TA.840_Key");
out.write(RSAEncrypted);
out.write(iv);
out.close();
Also, the AES key generated in java is different from the one generated via openssl. Can you guys please help.
EDIT 1:
Below is the code for AES Encrpytion used:
Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
byte[] AESEncrypted = AESCipher.doFinal(str.getBytes("UTF-8"));
String encryptedStr = new String(AESEncrypted);
The data that script and Java-code encrypt with RSA differ:
The script generates a random 48-bytes-sequence and stores it in the file 48byterandomvalue.bin. The first 32 bytes are used as AES key, the last 16 bytes as IV. Key and IV are used to encrypt the file PAYLOAD.zip with AES-256 in CBC-mode and store it as file PAYLOAD. The file 48byterandomvalue.bin is encrypted with RSA and stored as file 000000.00000.TA.840_Key.
In the Java-code, a random 32-bytes AES key and a random 16-bytes IV are generated. Both are used to perform the encryption with AES-256 in CBC-mode. The AES key is encrypted with RSA, concatenated with the unencrypted IV and the result is stored in the file 000000.00000.TA.840_Key.
The content of the file 000000.00000.TA.840_Key is different for script and Java-code. For the Java-code to generate the file 000000.00000.TA.840_Key with the script-logic, the unencrypted AES key must be concatenated with the unencrypted IV and this result must be encrypted with RSA:
...
//byte[] aesKeyb byte-array with random 32-bytes key
//byte[] iv byte-array with random 16-bytes iv
byte[] key_iv = new byte[aesKeyb.length + iv.length];
System.arraycopy(aesKeyb, 0, key_iv, 0, aesKeyb.length);
System.arraycopy(iv, 0, key_iv, aesKeyb.length, iv.length);
...
byte[] RSAEncrypted = RSACipher.doFinal(key_iv);
FileOutputStream out = new FileOutputStream("000000.00000.TA.840_Key");
out.write(RSAEncrypted);
out.close();
...
Note: The IV doesn't have to be secret and therefore doesn't need to be encrypted. The encryption is only necessary to generate the result of the script in the Java-code.
Another problem concerns the conversion of arbitrary binary data into strings. This generally leads to corrupted data if the encoding is unsuitable (e.g. ASCII or UTF8). Therefore
...
byte[] encoded = Files.readAllBytes(Paths.get(filePath));
str = new String(encoded, StandardCharsets.US_ASCII); // Doesn't work: ASCII (7-bit) unsuitable for arbitrary bytes, *
...
byte[] AESEncrypted = AESCipher.doFinal(str.getBytes("UTF-8")); // Doesn't work: UTF-8 unsuitable for arbitrary bytes and additionally different from *
String encryptedStr = new String(AESEncrypted); // Doesn't work: UTF-8 unsuitable for arbitrary bytes
...
should be replaced by
...
byte[] encoded = Files.readAllBytes(Paths.get(filePath));
...
byte[] AESEncrypted = AESCipher.doFinal(encoded);
FileOutputStream out = new FileOutputStream("PAYLOAD");
out.write(AESEncrypted);
out.close();
...
A suitable encoding to store arbitrary data in a string is e.g. Base64, but this isn't necessary in this case, because Base64-encoding isn't used in the script either.
Try these changes. If other issues occur, it would be best to test AES encryption, RSA encryption, and key_iv-generation separately. This makes it easier to isolate bugs.
I have a RSA generate key using the RSAKeyPairGenerator class. It returns a AsymmetricCipherKeyPair with the keys in AsymmetricKeyParameter objects. AsymmetricKeyParameter don't have anyone encode function for get the key in a byte array.
The wrap function only receive byte[] parameter. How do I serialize the key using the Lightweight?
RSAKeyPairGenerator keyGenerator = new RSAKeyPairGenerator();
keyGenerator.init(new RSAKeyGenerationParameters(new BigInteger("10001" ,16), new SecureRandom(), 2048, 80));
AsymmetricCipherKeyPair keys = keyGenerator.generateKeyPair();
AsymmetricKeyParameter priv = keys.getPrivate();
I am trying to encrypt some simple message with pidCrypt in browser, then decrypt it with java crypto on the server. But I kept getting the error message:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
Keys:
keys are generated with openssl genrsa (sslery).
The private key then converted to pkcs#8 der format and read into java code
JS code snippet:
/*---* ENCRYPT: RSA 1024 bit ---------*/
// public key
var params = certParser(publickey);
var key = pidCryptUtil.decodeBase64(params.b64);
// new RSA instance
var rsa = new pidCrypt.RSA();
/* RSA encryption
* get the modulus and exponent from certificate (ASN1 parsing)
* pem(Array of Bytes)
*/
// ASN1 parsing
var asn = pidCrypt.ASN1.decode(pidCryptUtil.toByteArray(key));
var tree = asn.toHexTree();
// setting the public key for encryption with retrieved ASN.1 tree
rsa.setPublicKeyFromASN(tree);
/*** encrypt */
var crypted = rsa.encrypt(plaintext);
//var crypted64 = pidCryptUtil.encodeBase64(crypted);
java code snippet:
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, myPrivKey);
byte[] descryptedData = cipher.doFinal(cyphertext.getBytes());
I'm trying to encrypt some binary data in Java with a public key as described on this useful page:
http://www.junkheap.net/content/public_key_encryption_java
As directed by the page, I created public and private keys using the commands:
openssl genrsa -aes256 -out private.pem 2048
openssl rsa -in private.pem -pubout -outform DER -out public.der
Now I save encrypt some data with a small program:
public class Rsa {
public static void main(String[] args) throws Exception, IOException {
File keyFile = new File("public.der");
byte[] encodedKey = new byte[(int) keyFile.length()];
new FileInputStream(keyFile).read(encodedKey);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(publicKeySpec);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, pk);
FileOutputStream fileOutputStream = new FileOutputStream(
"encrypted.rsa");
OutputStream os = new CipherOutputStream(fileOutputStream, rsa);
byte[] raw = new byte[245];
raw[0] = 4;
os.write(raw);
os.flush();
os.close();
}
}
The above code works, but when I change the size of the byte array to 246, it produces a zero-length file!
What am I doing wrong?
CipherOutputStream tends to swallow exceptions generated by the Cipher and OutputStream objects it wraps. The Sun RSA implementation will not encrypt more than than M-11 bytes, where M is the length in bytes of the modulus. This is true for the default PKCS1Padding, which is what you should always use unless you really know what you are doing. You can specify NoPadding and thereby get the full M bytes.
RSA is not the correct choice for encrypting bulk data. The generally accepted method for encrypting data with RSA is to generate a random symmetric session key K. e.g. an AES key, encrypt the data with the symmetric algorithm with K, then encrypt K using the RSA keys of all the receipients.