Hello,
Through several articles, I would like present the cryptographic mechanisms, types of keys, certificate, types of algorithms …etc:

 


Encryption with RSA (asymmetric keys private and public)
 

  1. Presentation
    RSA is an asymmetric cryptography algorithm, widely used in electronic commerce, and more generally to exchange confidential data on the Internet. This algorithm was described in 1977 by Ronald Rivest, Adi Shamir and Leonard Adleman. RSA was patented by the Massachusetts Institute of Technology (MIT) in 1983 in the United States. The patent expired on 21 September 2000.

    The RSA encryption uses a pair of keys (integers) composed of a public key to encrypt and a private key to decrypt confidential data. RSA is based on the difficulty of factorizing large numbers, and the one-way function used is a “power” function.

    The keys (public, private) keys are built via the following steps:
    1.Choose two distinct primes numbers : p and q
    2.Calculate the multiplication of this two numbers : n = p * q named encryption modulus
    3.Calculate φ(n) = (p – 1) * (q -1) (Value of the Euler indicator in ñ)
    4.Choose a natural integer e prime number with φ(n) and strictly lower to φ(n) : p,q < e < φn , pgcd(n,e) = 1, named encryption exponent
    5. Calculate the natural integer d, reverse of e modulo φ(n), and strictly lower to φ(n) : p,q < d < φn , e*d mod n = 1 named decryption exposant.
     
    These informations are accessible via the Java Object like sun.security.rsa.RSAPublicKeyImpl and sun.security.rsa.RSAPrivateCrtKeyImpl via the methods : getPublicExponent(), getPrimeExponentP(), getPrimeExponentQ(), getPrimeP(), getPrimeQ() …etc.
     
    Important note : The RSA encryption has a limitation linked to key’s length. For example, in our case, the size of RSA key’s length being 1024 bits / 128 bytes (1024/8), the max length of data to encrypt will be 128 – 11 = 117 bytes. If the length of data to encrypt is superior to 117 bytes, the encryption is going to throw a “javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes”.
     
     

  2. Tools
    As described in the post http://www.javablog.fr/javacrypto-encryption-list-providers-and-algo.html, we could find the available algorithm, tools (cipher, generator) in each reachable provider. In our case, we use the SunJCE Provider which is enough (http://javasearch.developpez.com/sun/j2se/1.6.0/technotes/guides/security/SunProviders.html#SunJCEProvider)
    The following algorithms are available in the SunJCE provider:

    [2] SunRsaSign v1.5: Sun RSA signature provider
    - KeyFactory.RSA -> sun.security.rsa.RSAKeyFactory
    aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
    - KeyPairGenerator.RSA -> sun.security.rsa.RSAKeyPairGenerator
    aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
    [3] SunJSSE v1.6: Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
    - KeyFactory.RSA -> sun.security.rsa.RSAKeyFactory
    aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
    - KeyPairGenerator.RSA -> sun.security.rsa.RSAKeyPairGenerator
    aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
    [4] SunJCE v1.6: SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
    - Cipher.RSA -> com.sun.crypto.provider.RSACipher
    attributes: {SupportedKeyClasses=java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey, SupportedPaddings=NOPADDING|PKCS1PADDING|OAEPWITHMD5ANDMGF1PADDING|OAEPWITHSHA1ANDMGF1PADDING|OAEPWITHSHA-1ANDMGF1PADDING|OAEPWITHSHA-256ANDMGF1PADDING|OAEPWITHSHA-384ANDMGF1PADDING|OAEPWITHSHA-512ANDMGF1PADDING, SupportedModes=ECB}
    - KeyGenerator.SunTlsRsaPremasterSecret -> com.sun.crypto.provider.TlsRsaPremasterSecretGenerator

     
  3. Example : Encryption of data via the algorithm “RSA/ECB/PKCS1Padding” on 1024bits

    … Code for the generation of public and private keys:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(1024);
    KeyPair keyPair = keyGen.genKeyPair();
    PublicKey publicKey = keyPair.getPublic();
    PrivateKey privateKey = keyPair.getPrivate();
    

    … some methods for encryption/ciphering with public key:

    • via the byte value of public key,
    • via the modulus and exponent elements of public key,
    • via directly the public key,
        public static byte[] encrypt(byte[] keyValue, byte[] data) throws Exception {
        	// Constrution of PublicKey from byte[]
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        	PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyValue));
            return encrypt(publicKey, data);
        }
    
        public static byte[] encrypt(BigInteger modpublic, BigInteger exppublic, byte[] data) throws Exception {
        	// Constrution of PublicKey from modulus and Exponent
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modpublic, exppublic);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return encrypt(publicKey, data);
        }
    
        public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
        	Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encVal = c.doFinal(data);
            return encVal;
        }    
    

     
    … some methods for decryption/deciphering with private key:

    • via the byte value of private key,
    • via the the modulus and exponent elements of private key,
    • via directly the private key,
    	
        public static byte[] decrypt(byte[] keyValue, byte[] encryptedData) throws Exception {
        	// Constrution of PrivateKey from byte[]
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        	PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyValue));
            return decrypt(privateKey, encryptedData);
        }
    
        public static byte[] decrypt(BigInteger modprivate, BigInteger expprivate, byte[] encryptedData) throws Exception {
        	// Constrution of PrivateKey from modulus and Exponent
            RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modprivate, expprivate);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return decrypt(privateKey, encryptedData);
        }
    
        public static byte[] decrypt(PrivateKey privateKey, byte[] encryptedData) throws Exception {
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decValue = c.doFinal(encryptedData);
            return decValue;
        }
    

     


     
    …here a TEST 1 of encryption/decryption with directly the public and private keys:

    //Generation of keys
    PublicKey publicKey = ....;
    System.out.println("Public key =" + ((sun.security.rsa.RSAPublicKeyImpl)publicKey));
    PrivateKey privateKey = ...;
    System.out.println("Private key =" + ((sun.security.rsa.RSAPrivateCrtKeyImpl)privateKey));
    
    // Data
    String sourceData = "123456ds fds àçèé#&çer çer "+System.getProperty("line.separator")+" ^rrr 7897ezrz";
    System.out.println("Original=" + sourceData);
    
    // Encrypt data
    byte[] encryptData = EncryptionRsaEcbPkcs1Padding.encrypt(publicKey, sourceData.getBytes());
    System.out.println("Encoded=" + new String(encryptData));
    		
    // Decrypt data
    byte[] decryptData = EncryptionRsaEcbPkcs1Padding.decrypt(privateKey, encryptData);
    String finalData = (decryptData!=null)? new String(decryptData):"";
    System.out.println("Decoded=" + finalData);
    		
    System.out.println("Decoded is equal to Original=" + (finalData.equals(sourceData)));

     
    …here the outputs:
    Public key =Sun RSA public key, 1024 bits
    modulus: 108236464083379203986747740102294506670642332644595091140477437212401770341725043446331666439922563601662126192294403912678804313052165471480180527273763676015029833044710156310334154567843847063265648379340267370388318243580677624706287519462429736743486286443163528711213522234983714241340528082087997553997

    public exponent: 65537
    Private key =sun.security.rsa.RSAPrivateCrtKeyImpl@a763d

    Original=123456ds fds àçèé#&çer çer
    ^rrr 7897ezrz

    Encoded=bU,DÝF¡üá?œì"±\+°-Rµ½™Ý¾CÞªhŽûS‹+©à1qlvE0Ô~áMm&À4éAÎŒ!œè,TWP»5ž[ïvù`ȧÂîøxa‚‡ƒáwÛÕ‰j{brûBŽ¹Ä¦•®¡wàfÂkE*Õ´êf1¥qB?ì®

    Decoded=123456ds fds àçèé#&çer çer
    ^rrr 7897ezrz

    Decoded is equal to Original=true

     


     
    …here a TEST 2 of encryption/decryption with the byte value of public and private keys:

    //Generation of keys
    PublicKey publicKey = ....;
    System.out.println("Public key =" + ((sun.security.rsa.RSAPublicKeyImpl)publicKey));
    PrivateKey privateKey = ...;
    System.out.println("Private key =" + ((sun.security.rsa.RSAPrivateCrtKeyImpl)privateKey));
    
    // Data
    String sourceData = "123456ds fds àçèé#&çer çer "+System.getProperty("line.separator")+" ^rrr 7897ezrz";
    System.out.println("Original=" + sourceData);
    
    // Encrypt data
    byte[] encryptData = EncryptionRsaEcbPkcs1Padding.encrypt(publicKey.getEncoded(), sourceData.getBytes());
    System.out.println("Encoded=" + new String(encryptData));
    		
    // Decrypt data
    byte[] decryptData = EncryptionRsaEcbPkcs1Padding.decrypt(privateKey.getEncoded(), encryptData);
    String finalData = (decryptData!=null)? new String(decryptData):"";
    System.out.println("Decoded=" + finalData);
    		
    System.out.println("Decoded is equal to Original=" + (finalData.equals(sourceData)));
    

     
    …here the outputs:
    Public key =Sun RSA public key, 1024 bits
    modulus: 97392577533464847212159666283371265312195963457783867011563594880101035071664888285246165055268403437113791299196226113467171554262215338665624196367846941742826902988371223917394549714601526511256658364514894511973625205592508082767463020431470353350647479947777222505844148608989650023898960716372820993061
    public exponent: 65537

    Private key =sun.security.rsa.RSAPrivateCrtKeyImpl@278ef

    Original=123456ds fds àçèé#&çer çer
    ^rrr 7897ezrz

    Encoded=¤jðЯ‘Å_Ô³o[Ã× d;¡:¶´I?É<ù›þ’sú–òÍC’(ü2ÿ7…2d|¼ù?ËrßÛiÚ>r0áRyò„têAÌÑ«+Á^l¸Zòç ½¶å»yÇÆË?µ7Ÿ¯®Ú‘äv)G{Ý›©'åÒ»>ð2àˆ¦æL-ž??œ

    Decoded=123456ds fds àçèé#&çer çer
    ^rrr 7897ezrz

    Decoded is equal to Original=true

     


     
    …here a TEST 3 of encryption/decryption with the modulus and exponent elements of public and private keys:

    //Generation of keys
    PublicKey publicKey = ....;
    System.out.println("Public key =" + ((sun.security.rsa.RSAPublicKeyImpl)publicKey));
    PrivateKey privateKey = ...;
    System.out.println("Private key =" + ((sun.security.rsa.RSAPrivateCrtKeyImpl)privateKey));
    
    // Get the modulus and Exponent of public and private keys
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPublicKeySpec rsaPubKeySpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);
    BigInteger modpublic = rsaPubKeySpec.getModulus(); // = ((RSAPublicKey)publicKey).getModulus());
    BigInteger exppublic = rsaPubKeySpec.getPublicExponent(); // = ((RSAPublicKey)publicKey).getPublicExponent());
    
    RSAPrivateKeySpec rsaPrivKeySpec = keyFactory.getKeySpec(privateKey, RSAPrivateKeySpec.class);
    BigInteger modprivate = rsaPrivKeySpec.getModulus(); // = ((RSAPrivateKey)privateKey).getModulus();
    BigInteger expprivate = rsaPrivKeySpec.getPrivateExponent(); // = ((RSAPrivateKey)privateKey).getPrivateExponent();
    
    System.out.println(" **** RSAPublicKey:");
    System.out.println(" Modulus public : " + modpublic);
    System.out.println(" Exponent public : " + exppublic);
    System.out.println(" **** RSAPrivateKey:");
    System.out.println(" Modulus private : " + modprivate);
    System.out.println(" Exponent private : " + expprivate);
    		
    // Data
    String sourceData = "123456ds fds àçèé#&çer çer "+System.getProperty("line.separator")+" ^rrr 7897ezrz";
    System.out.println("Original=" + sourceData);
    
    // Encrypt data
    byte[] encryptData = EncryptionRsaEcbPkcs1Padding.encrypt(modpublic, exppublic, sourceData.getBytes());
    System.out.println("Encoded=" + new String(encryptData));
    		
    // Decrypt data
    byte[] decryptData = EncryptionRsaEcbPkcs1Padding.decrypt(modprivate, expprivate, encryptData);
    String finalData = (decryptData!=null)? new String(decryptData):"";
    System.out.println("Decoded=" + finalData);
    		
    System.out.println("Decoded is equal to Original=" + (finalData.equals(sourceData)));
    

     
    …here the outputs:
    Public key =Sun RSA public key, 1024 bits
    modulus: 119640545002572524162074876403590977724521819906953835044584334393673056623269874048551575214466583338692013946864923643869629755417250776762852900928975400221212653461763170363707824634941857579752131353812321189962302470921868983432333273212462165196125740045294389745266851969500869704002993658134669956039
    public exponent: 65537

    Private key =sun.security.rsa.RSAPrivateCrtKeyImpl@fff5a677

    **** RSAPublicKey:

    Modulus public : 119640545002572524162074876403590977724521819906953835044584334393673056623269874048551575214466583338692013946864923643869629755417250776762852900928975400221212653461763170363707824634941857579752131353812321189962302470921868983432333273212462165196125740045294389745266851969500869704002993658134669956039

    Exponent public : 65537

    **** RSAPrivateKey:

    Modulus private : 119640545002572524162074876403590977724521819906953835044584334393673056623269874048551575214466583338692013946864923643869629755417250776762852900928975400221212653461763170363707824634941857579752131353812321189962302470921868983432333273212462165196125740045294389745266851969500869704002993658134669956039

    Exponent private : 108868021755243832505752434948266651625487636784886383366935187236234286048878072062490222919723654790213725738670317323432705801212493207242160849593365208277168149271759733306735434932388171411986171035282651184823939882411859771870386758804259331674797713118041333080648290829593352145662020438209090922113

    Original=123456ds fds àçèé#&çer çer
    ^rrr 7897ezrz

    Encoded=~2i
    ¤ÕìÁù$62?Î4­ÝGO?Ô€ƒ&¥?šWµŠ]¿
    wÞãøŽï¡S
    ....

    Decoded=123456ds fds àçèé#&çer çer
    ^rrr 7897ezrz

    Decoded is equal to Original=true

  4.  
     
     

  5. Error and limitation of RSA
    If the following error occurs during the execution of your code:

    ERROR : javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes
    	at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:346)
    	at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
    	at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    

     
    ….EXPLANATIONS:
    The RSA algorithm can only encrypt data that has a maximum byte length of the RSA key length in bits divided with eight minus eleven padding bytes, i.e. number of maximum bytes = key length in bits / 8 – 11. In previous examples, our RSA keys were generated on 1024 bites = 128 bytes, so, the maximum byte length of data to encrypt is : 1024 / 8 – 11 = 128 – 11 = 117 bytes.
     
    SOLUTIONS:
    So, 2 solutions are possibles:
    + use a larger RSA key
    + OR encrypt the data with a symmetric key, and encrypt that key with RSA (recommended approach). That will require to:

    1. Generate a symmetric key
    2. Encrypt the data with the symmetric key
    3. Encrypt the symmetric key with RSA
    4. Send the encrypted key and the data
    5. Decrypt the encrypted symmetric key with RSA
    6. Decrypt the data with the symmetric key

Sources : rsa.zip

That’s all!!!

Huseyin OZVEREN