001package lucee.commons.digest;
002
003import java.io.IOException;
004import java.security.InvalidKeyException;
005import java.security.KeyFactory;
006import java.security.KeyPair;
007import java.security.KeyPairGenerator;
008import java.security.NoSuchAlgorithmException;
009import java.security.PrivateKey;
010import java.security.PublicKey;
011import java.security.spec.InvalidKeySpecException;
012import java.security.spec.PKCS8EncodedKeySpec;
013import java.security.spec.X509EncodedKeySpec;
014import java.util.ArrayList;
015import java.util.Iterator;
016import java.util.List;
017
018import javax.crypto.BadPaddingException;
019import javax.crypto.Cipher;
020import javax.crypto.IllegalBlockSizeException;
021import javax.crypto.NoSuchPaddingException;
022
023import lucee.runtime.coder.CoderException;
024
025public class RSA {
026                
027        private static final int KEY_SIZE = 1024;
028
029        public static String toString(PrivateKey privateKey) {
030                PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
031                return toString(pkcs8EncodedKeySpec.getEncoded());
032        }
033        
034        public static String toString(PublicKey publicKey) {
035                X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
036                return toString(x509EncodedKeySpec.getEncoded());
037        }
038        
039        public static PrivateKey toPrivateKey(String privateKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
040                byte[] bytes = toBytes(privateKey);
041                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
042                PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(bytes);
043                return keyFactory.generatePrivate(privateKeySpec);
044        }
045        
046        public static PublicKey toPublicKey(String publicKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
047                byte[] bytes = toBytes(publicKey);
048                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
049                X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(bytes);
050                return keyFactory.generatePublic(publicKeySpec);
051        }
052
053        private static String toString(byte[] barr) {
054                return Base64Encoder.encode(barr);
055        }
056
057        private static byte[] toBytes(String str) throws CoderException {
058                return Base64Encoder.decode(str);
059        }
060
061        public static KeyPair createKeyPair() throws NoSuchAlgorithmException {
062                KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
063            kpg.initialize(KEY_SIZE);
064            return kpg.genKeyPair();
065        }
066        
067        public static byte[] encrypt(byte[] data, PrivateKey privateKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
068                Cipher cipher = Cipher.getInstance("RSA");
069            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
070            int max=(KEY_SIZE/8)-11;
071            
072            // we need to split in pieces, because RSA cannot handle pices bigger than the key size
073            List<byte[]> list=new ArrayList<byte[]>();
074            int offset=0,len=data.length,l,total=0;
075            byte[] part;
076            while(offset<len) {
077                l=len-offset<max?len-offset:max;
078                part=cipher.doFinal(data, offset, l);
079                total+=part.length;
080                list.add(part);
081                offset+=l;
082            }
083            
084            // now we merge to one piece
085            byte[] bytes=new byte[total];
086            Iterator<byte[]> it = list.iterator();
087            int count=0;
088            while(it.hasNext()){
089                part=it.next();
090                for(int i=0;i<part.length;i++){
091                        bytes[count++]=part[i];
092                }
093            }
094            
095            
096            return bytes;
097        }
098        
099        public static byte[] decrypt(byte[] data, PublicKey publicKey, int offset) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
100                int max=(KEY_SIZE/8);
101                Cipher cipher = Cipher.getInstance("RSA");
102            cipher.init(Cipher.DECRYPT_MODE, publicKey);
103            
104            
105            // we need to split in pieces, because RSA cannot handle pieces bigger than the key size
106            List<byte[]> list=new ArrayList<byte[]>();
107            int off=offset,len=data.length,l,total=0;
108            byte[] part;
109            while(off<len) {
110                l=len-off<max?len-off:max;
111                part=cipher.doFinal(data, off, l);
112                total+=part.length;
113                list.add(part);
114                off+=l;
115            }
116
117            // now we merge to one piece
118            byte[] bytes=new byte[total];
119            Iterator<byte[]> it = list.iterator();
120            int count=0;
121            while(it.hasNext()){
122                part=it.next();
123                for(int i=0;i<part.length;i++){
124                        bytes[count++]=part[i];
125                }
126            }
127            
128            return bytes;
129        }
130        
131        /*public static void main(String[] args) throws Exception {
132                KeyPair kp = createKeyPair();
133                String str="";
134                for(int i=0;i<=1700;i++) {
135                        
136                        str+=i+"Hello there how are you?\n";
137                }
138                byte[] bytes = str.getBytes();
139                
140                long start=System.currentTimeMillis();
141                byte[] enc = encrypt(bytes, kp.getPrivate());
142
143                System.out.println(enc.length);
144                byte[] dec = decrypt(enc, kp.getPublic());
145                System.out.println(new String(dec));
146                System.out.println("->"+(System.currentTimeMillis()-start));
147        }*/
148                  
149}