'PKCS'에 해당되는 글 2건

  1. 2015.11.05 RSA 암호화
  2. 2015.11.05 base64 인코딩, 디코딩의 원리

RSA 암호화

카테고리 없음 2015. 11. 5. 10:57

RSA 파일 암호화

 

     RSA 키 쌍 생성

 

     공개 키로 파일을 암호화

가)    RSA 키의 인코딩

     X.509를 사용하여 인코딩 사용(공개 키와 인증서를 전달할 때 사용하는 공개 형식)

     개인 키는 PKCS#8로 인코딩

     공개/개인 키든 getEncoded()를 호출하면 자동으로 인코딩 됨

나)    RSA 키의 디코딩

     인코딩된 키의 스펙 객체를 생성

     KeyFactory를 사용하여 적절한 키 타입의 인스턴스를 활성화

     공개 키 디코딩

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);

PublicKey publicKey = keyFactory.generatePublic(keySpec);

 

     개인 키의 디코딩

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);

PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

 

다)    암호화된 파일 형식

     포맷

키의 길이

암호화된 키

초기화백터(16바이트)

암호문서

 

라)    예제

private static void createKey(String password) throws Exception {

             // RSA 생성

             KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

             keyPairGenerator.initialize(1024);

             KeyPair keyPair = keyPairGenerator.genKeyPair();

            

             //공개키를 파일에 쓴다.

             byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

             FileOutputStream fos = new FileOutputStream("c:\\publicKey");

             fos.write(publicKeyBytes);

             fos.close();

            

             // 개인 키를 암호화한 후에 파일에 쓴다.

             byte[] privateKeyBytes = passwordEncrypt(password.toCharArray(), keyPair.getPrivate().getEncoded());

             fos = new FileOutputStream("c:\\privateKey");

             fos.write(publicKeyBytes);

             fos.close();

       }

      

       private static byte[] passwordEncrypt(char[] password, byte[] plaintext) throws Exception {

             // salt 생성

             byte[] salt = new byte[9];

             Random random = new Random();

             random.nextBytes(salt);

            

             // PBE 키와 사이퍼 생성

             PBEKeySpec keySpec = new PBEKeySpec(password);

             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC");

             SecretKey key = keyFactory.generateSecret(keySpec);

             PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);

            

             Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC");

             cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

            

             byte[] cipherText = cipher.doFinal(plaintext);

            

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

             baos.write(salt);

             baos.write(cipherText);

            

            

             return baos.toByteArray();

       }

      

       private static void encrypt(String fileInput) throws Exception {

             String publicKeyFileName = "c:\\publicKey";

             // 공개 키가 저장된 파일로부터 keyByte 바이트 배열을 생성한다.

             FileInputStream fis = new FileInputStream(publicKeyFileName);

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

            

             int theByte = 0;

             while((theByte = fis.read()) != -1)

                    baos.writeTo(baos);

             fis.close();

            

             byte[] keyBytes = baos.toByteArray();

             baos.close();

            

             // 인코딩된 키를 RSA 공개 키의 인스턴스로 바꾼다.

             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

             KeyFactory keyFactory = KeyFactory.getInstance("RSA");

             PublicKey publicKey = keyFactory.generatePublic(keySpec);

            

             String fileOutput = fileInput + ENCRYPTED_FILENAME_SUFFIX;

             DataOutputStream output = new DataOutputStream(new FileOutputStream(fileOutput));

            

             // RSA 공개 키를 이용하여 세션 키를 암호화할 사이퍼를 생성한다.

             Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

             rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);

            

             // 세션 생성

             KeyGenerator rijndaelKeyGenerator = KeyGenerator.getInstance("Rijndael");

             rijndaelKeyGenerator.init(256);

             Key rijndaelKey = rijndaelKeyGenerator.generateKey();

            

             // RSA 사이퍼를 이용하여 세션 키를 암호화 하고 파일에 저장한다.

             // 키의 길이, 인코딩된 세션 형식이다.

             byte[] encodedKeyBytes = rsaCipher.doFinal(rijndaelKey.getEncoded());

             output.writeInt(encodedKeyBytes.length);

             output.write(encodedKeyBytes);

            

             // 초기화 벡터

             SecureRandom random = new SecureRandom();

             byte[] iv = new byte[16];

             random.nextBytes(iv);

            

             //IV 파일에 쓴다

             output.write(iv);

            

             //IV 생성한 세션 키를 이용하여 파일의 내용을 암호화한다.

             IvParameterSpec spec = new IvParameterSpec(iv);

             Cipher symmetricCipher = Cipher.getInstance("Rijndael/CBC/PKCS5Padding");

             symmetricCipher.init(Cipher.ENCRYPT_MODE, rijndaelKey, spec);

             CipherOutputStream cos = new CipherOutputStream(output, symmetricCipher);

            

             FileInputStream input = new FileInputStream(fileInput);

             theByte = 0;

             while((theByte = input.read()) != -1)

                    cos.write(theByte);

            

             input.close();

             cos.close();

             return;

       }

 

     개인 키로 복호화

가)    예제

private static byte[] passwordDecrypt(char[] password, byte[] ciphertext) throws Exception {

             // salt 읽는다. 개인키는 8byte salt 사용했다.

             byte[] salt = new byte[8];

             ByteArrayInputStream bais = new ByteArrayInputStream(ciphertext);

             bais.read(salt, 0 ,8);

            

             byte[] remainingCiphertext = new byte[ciphertext.length-8];

             bais.read(remainingCiphertext, 0, ciphertext.length-8);

            

             //PBE 사이퍼를 생성하여 세션 키를 복원한다.

             PBEKeySpec keySpec = new PBEKeySpec(password);

             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC");

             SecretKey key = keyFactory.generateSecret(keySpec);

             PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);

             Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC");

            

             // 복호화

             cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

             return cipher.doFinal(remainingCiphertext);

       }

      

       private static void decrypt(String password, String fileInput) throws Exception {

             String privateKeyFilename = "c:\\privateKey";

             // 파일로부터 개인 키를 읽어들인다.

             FileInputStream fis = new FileInputStream(privateKeyFilename);

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

            

             int theByte = 0;

             while((theByte = fis.read()) != -1)

                    baos.write(theByte);

             fis.close();

             byte[] keyByte = baos.toByteArray();

             baos.close();

            

              // 암호화된 개인 바이트를 복원한다.

             keyByte = passwordDecrypt(password.toCharArray(), keyByte);

            

             // RSA 개인 키를 복원한다.

             PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyByte);

             KeyFactory keyFactory = KeyFactory.getInstance("RSA");

             PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

            

             // 개인 키를 이용하여 사이퍼를 생성하고 세션 키를 복호화한다

             Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

             DataInputStream dis = new DataInputStream(new FileInputStream(fileInput));

             byte[] encryptedKeyBytes = new byte[dis.readInt()];

             dis.readFully(encryptedKeyBytes);

            

             rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);

             byte[] rijndaelKeyByte = rsaCipher.doFinal(encryptedKeyBytes);

            

             SecretKey rijndaelKey = new SecretKeySpec(rijndaelKeyByte, "Rijndael");

            

             byte[] iv = new byte[16];

             dis.readFully(iv);

             IvParameterSpec spec = new IvParameterSpec(iv);

            

             Cipher cipher = Cipher.getInstance("Rijndael/CBC/PKCS5padding");

             cipher.init(Cipher.DECRYPT_MODE, rijndaelKey, spec);

             CipherInputStream cis = new CipherInputStream(dis, cipher);

            

             FileOutputStream fos = new FileOutputStream(fileInput + DECRYPTED_FILENAME_SUFFIX);

            

             theByte = 0;

             while((theByte = cis.read()) != -1)

                    fos.write(theByte);

            

             cis.close();

             fos.close();

            

             return;     

       }

 

나)    복호화 과정

 

     세션 키 암호화를 사용해야 하는 이유

가)    해킹에 대비해, 개인 키를 저장할 때 암호화할 필요가 있다.

나)    세션 키를 사용하면 속도가 훨씬 빨라진다.

다)    RSA는 특정 메시지에 대해서 매우 취약하다.

 

Posted by 으랏차
,

출처 및 참조 : http://www.iamcorean.net/130

출처 및 참조 : http://huikyun.tistory.com/70

Base64 구현코드 : 첨부파일(zip)을 그대로 등록하시면 됩니다.

 

1. 원리는 뭘까요?

 

일반적으로 컴퓨터는 byte라고 하는 8bit를 기준으로 데이터를 표한하는 것이 일반적입니다.

8bit로 표현하는 데이터를 6bit로 표현하겠다는 겁니다.

 

8bit와 6bit의 최소 공배수는 24bit입니다.

즉 입력된 byte 문자열을 24bit 단위로 잘라서 다시 6bit씩 잘라서 표에 따라 문자로 변환해줍니다. 

아래 그림을 보면 글자 3개 24bit를 다시 6bit 문자 4개로 나누고 있습니다.

 

그럼 실제로 바꿔 볼까요?

step1) 먼저 예를 들면 "abc"는 8bit 문자로 구성된 byte 문자열 입력입니다.

step2) 그럼 이 값은 각 문자를 의미하는 8bit 이진값으로 표현됩니다.

step3) 이를 6bit 단위로 다시 구분합니다

step4) 이를 base64 문자셋으로 변환합니다 아래의 표를 참조하세요 

 

 

 

step4) 만약 24bit가 아니라면?

BASE64 인코딩은 항상 24bit 단위로 수행합니다.

그래서 남는 비트가 생기면 남은 bit를 0으로 패딩합니다.

모든 bit가 0인 6bit 문자는 '=' 으로 치환됩니다.

 



암호화 공부하다가 옆길로 샜어... ㅠ.ㅠ

오늘도 이렇게 날리는 구나...

 

출처 :http://blog.naver.com/xxrcn11?Redirect=Log&logNo=20134786143

'UP! > Crypto' 카테고리의 다른 글

패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
인증, 전자서명  (0) 2015.11.05
대칭 비대칭 암호화  (0) 2015.11.05
블록 Padding  (0) 2015.11.05
Posted by 으랏차
,