Android Rsa 데이터 복호화 에 대한 소개 및 사용 예시

Rsa 암호 화
RSA 는 현재 가장 영향력 있 는 공개 키 암호 화 알고리즘 으로 RSA 도 데이터 암호 화 와 디지털 서명 에 사용 할 수 있 는 첫 번 째 알고리즘 이다.이 알고리즘 은 매우 간단 한 수론 사실 을 바탕 으로 한다.두 개의 큰 소 수 를 곱 하 는 것 은 매우 쉽 지만 그 때 는 그 곱 하기 에 대해 인수 분 해 를 하려 고 했 지만 매우 어 려 웠 기 때문에 곱 하기 공 개 를 암호 화 키,즉 공개 키 로 할 수 있 고 두 개의 큰 소수 그룹 은 비밀 키 로 합성 할 수 있다.공개 키 는 발표 할 수 있 는 사람 이 사용 할 수 있 는 것 이 고 비밀 키 는 자신의 소유 이 며 복호화 에 사용 할 수 있 습 니 다.
RSA 알고리즘 원리
     1.무 작위 로 두 개의 대질 수 p 와 q 를 선택 하고 p 는 q 와 같 지 않 으 며 N=pq 를 계산한다.
     2.1 보다 작은 자연수 e 를 선택 하고 e 는(p-1)(q-1)과 호소해 야 합 니 다.
     3.공식 으로 d:d 를 계산한다.×e = 1 (mod (p-1)(q-1)) 。
     4.p 와 q 를 소각 합 니 다.
최종 적 으로 얻 은 N 과 e 는'공개 키'이 고 d 는'비밀 키'이다.발송 자 는 N 을 사용 하여 데 이 터 를 암호 화하 고 수신 자 는 d 를 사용 해 야 데이터 내용 을 풀 수 있다.
RSA 의 안전성 은 대수 분해 에 의존 하고 1024 비트 이하 의 N 은 안전 하지 않 은 것 으로 증명 되 었 으 며 RSA 알고리즘 이 모두 대수 계산 을 하기 때문에 RSA 가 가장 빠 른 상황 도 DES 보다 배 느 려 졌 다.이것 은 RSA 의 가장 큰 결함 이기 때문에 보통 소량의 데이터 나 암호 화 키 만 암호 화 할 수 있 지만 RSA 는 여전히 강도 가 높 은 알고리즘 이 라 고 할 수 있다.
Rsa 사용
우선 비밀 키 쌍 생 성

  /**
   *     RSA   
   *
   * @param keyLength     ,  :512~2048
   *           1024
   * @return
   */
  public static KeyPair generateRSAKeyPair(int keyLength) {
    try {
      KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
      kpg.initialize(keyLength);
      return kpg.genKeyPair();
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
      return null;
    }
  }
구체 적 인 암호 화 실현:
공개 키 암호 화

  /**
   *            
   *
   * @param data   
   */
  public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
    //     
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
    KeyFactory kf = KeyFactory.getInstance(RSA);
    PublicKey keyPublic = kf.generatePublic(keySpec);
    //     
    Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
    cp.init(Cipher.ENCRYPT_MODE, keyPublic);
    return cp.doFinal(data);
  }
비밀 키 암호 화

  /**
   *     
   *
   * @param data         
   * @param privateKey   
   * @return byte[]     
   */
  public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
    //     
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
    KeyFactory kf = KeyFactory.getInstance(RSA);
    PrivateKey keyPrivate = kf.generatePrivate(keySpec);
    //     
    Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
    cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
    return cipher.doFinal(data);
  }
공개 키 복호화

 /**
   *     
   *
   * @param data        
   * @param publicKey   
   * @return byte[]     
   */
  public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
    //     
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
    KeyFactory kf = KeyFactory.getInstance(RSA);
    PublicKey keyPublic = kf.generatePublic(keySpec);
    //     
    Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
    cipher.init(Cipher.DECRYPT_MODE, keyPublic);
    return cipher.doFinal(data);
  }
비밀 키 복호화

 /**
   *         
   */
  public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
    //     
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
    KeyFactory kf = KeyFactory.getInstance(RSA);
    PrivateKey keyPrivate = kf.generatePrivate(keySpec);

    //     
    Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
    cp.init(Cipher.DECRYPT_MODE, keyPrivate);
    byte[] arr = cp.doFinal(encrypted);
    return arr;
  }
전역 변수 설명:

  public static final String RSA = "RSA";//          
  public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//      
  public static final int DEFAULT_KEY_SIZE = 2048;//      
  public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes();  //          bufferSize,   partSplit      
  public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;//               
암호 화 충전 방식
그 전에 이런 조작 으로 rsa 복호화 가 이 루어 질 줄 알 았 는데 만사 가 다 잘 될 줄 알 았 습 니 다.하하,이 일 은 아직 끝나 지 않 았 습 니 다.비극 이 발생 했 습 니 다.안 드 로 이 드 쪽 에서 암호 화 된 데 이 터 는 서버 측 에서 필사적으로 복호화 할 수 없습니다.원래 안 드 로 이 드 시스템 의 RSA 실현 은'RSA/NO/NoPadding'이 고 표준 JDK 실현 은'RSA/NO/PCS1Padding'입 니 다.이것 은 안 드 로 이 드 기기 에서 암호 화 된 후 서버 에서 복호화 할 수 없 는 원인 을 초래 하 였 으 므 로 이 를 실현 할 때 반드시 주의해 야 합 니 다.
세그먼트 암호 화 실현
충전 방식 을 해결 한 후에 자신 있 게 만사 가 잘 되 었 다 고 생각 했 습 니 다.그러나 의외 의 일이 발생 했 습 니 다.RSA 비대 칭 암호 화 내용 의 길 이 는 제한 이 있 습 니 다.1024 비트 key 는 최대 127 비트 의 데 이 터 를 암호 화 할 수 있 습 니 다.그렇지 않 으 면 잘못 보고 할 수 있 습 니 다(javax.crypto.IllegalBlock Size Exception:Data must be longer than 117 bytes).RSA 는 자주 사용 하 는 비대 칭 암호 화 알고리즘 입 니 다.최근 사용 할 때'부정 확 한 길이'의 이상 이 발생 했 는데 암호 화 된 데이터 가 너무 길 어서 그런 것 으로 나 타 났 다.RSA 알고리즘 에 따 르 면 암호 화 된 바이트 수 는 키 의 길 이 를 8 로 나 눈 다음 11(즉,KeySize/8-11)을 빼 면 안 되 고 암호 화 된 후에 비밀문서 의 바이트 수 를 얻 으 면 키 의 길이 값 을 8(즉,KeySize/8)로 나 눌 수 있 습 니 다.
공개 키 세그먼트 암호 화

/**
   *              
   *
   */
  public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception {
    int dataLen = data.length;
    if (dataLen <= DEFAULT_BUFFERSIZE) {
      return encryptByPublicKey(data, publicKey);
    }
    List<Byte> allBytes = new ArrayList<Byte>(2048);
    int bufIndex = 0;
    int subDataLoop = 0;
    byte[] buf = new byte[DEFAULT_BUFFERSIZE];
    for (int i = 0; i < dataLen; i++) {
      buf[bufIndex] = data[i];
      if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
        subDataLoop++;
        if (subDataLoop != 1) {
          for (byte b : DEFAULT_SPLIT) {
            allBytes.add(b);
          }
        }
        byte[] encryptBytes = encryptByPublicKey(buf, publicKey);
        for (byte b : encryptBytes) {
          allBytes.add(b);
        }
        bufIndex = 0;
        if (i == dataLen - 1) {
          buf = null;
        } else {
          buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
        }
      }
    }
    byte[] bytes = new byte[allBytes.size()];
    {
      int i = 0;
      for (Byte b : allBytes) {
        bytes[i++] = b.byteValue();
      }
    }
    return bytes;
  }
비밀 키 세그먼트 암호 화

 /**
   *     
   *
   * @param data            
   * @param privateKey   
   */
  public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
    int dataLen = data.length;
    if (dataLen <= DEFAULT_BUFFERSIZE) {
      return encryptByPrivateKey(data, privateKey);
    }
    List<Byte> allBytes = new ArrayList<Byte>(2048);
    int bufIndex = 0;
    int subDataLoop = 0;
    byte[] buf = new byte[DEFAULT_BUFFERSIZE];
    for (int i = 0; i < dataLen; i++) {
      buf[bufIndex] = data[i];
      if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
        subDataLoop++;
        if (subDataLoop != 1) {
          for (byte b : DEFAULT_SPLIT) {
            allBytes.add(b);
          }
        }
        byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
        for (byte b : encryptBytes) {
          allBytes.add(b);
        }
        bufIndex = 0;
        if (i == dataLen - 1) {
          buf = null;
        } else {
          buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
        }
      }
    }
    byte[] bytes = new byte[allBytes.size()];
    {
      int i = 0;
      for (Byte b : allBytes) {
        bytes[i++] = b.byteValue();
      }
    }
    return bytes;
  }
공개 키 세그먼트 복호화

 /**
   *       
   *
   * @param encrypted      
   * @param publicKey   
   */
  public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
    int splitLen = DEFAULT_SPLIT.length;
    if (splitLen <= 0) {
      return decryptByPublicKey(encrypted, publicKey);
    }
    int dataLen = encrypted.length;
    List<Byte> allBytes = new ArrayList<Byte>(1024);
    int latestStartIndex = 0;
    for (int i = 0; i < dataLen; i++) {
      byte bt = encrypted[i];
      boolean isMatchSplit = false;
      if (i == dataLen - 1) {
        //  data    
        byte[] part = new byte[dataLen - latestStartIndex];
        System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
        byte[] decryptPart = decryptByPublicKey(part, publicKey);
        for (byte b : decryptPart) {
          allBytes.add(b);
        }
        latestStartIndex = i + splitLen;
        i = latestStartIndex - 1;
      } else if (bt == DEFAULT_SPLIT[0]) {
        //     split[0]  
        if (splitLen > 1) {
          if (i + splitLen < dataLen) {
            //     data   
            for (int j = 1; j < splitLen; j++) {
              if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
                break;
              }
              if (j == splitLen - 1) {
                //    split     ,   break,        split 
                isMatchSplit = true;
              }
            }
          }
        } else {
          // split    ,      
          isMatchSplit = true;
        }
      }
      if (isMatchSplit) {
        byte[] part = new byte[i - latestStartIndex];
        System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
        byte[] decryptPart = decryptByPublicKey(part, publicKey);
        for (byte b : decryptPart) {
          allBytes.add(b);
        }
        latestStartIndex = i + splitLen;
        i = latestStartIndex - 1;
      }
    }
    byte[] bytes = new byte[allBytes.size()];
    {
      int i = 0;
      for (Byte b : allBytes) {
        bytes[i++] = b.byteValue();
      }
    }
    return bytes;
  }
비밀 키 세그먼트 복호화

 /**
   *         
   *
   */
  public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception {
    int splitLen = DEFAULT_SPLIT.length;
    if (splitLen <= 0) {
      return decryptByPrivateKey(encrypted, privateKey);
    }
    int dataLen = encrypted.length;
    List<Byte> allBytes = new ArrayList<Byte>(1024);
    int latestStartIndex = 0;
    for (int i = 0; i < dataLen; i++) {
      byte bt = encrypted[i];
      boolean isMatchSplit = false;
      if (i == dataLen - 1) {
        //  data    
        byte[] part = new byte[dataLen - latestStartIndex];
        System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
        byte[] decryptPart = decryptByPrivateKey(part, privateKey);
        for (byte b : decryptPart) {
          allBytes.add(b);
        }
        latestStartIndex = i + splitLen;
        i = latestStartIndex - 1;
      } else if (bt == DEFAULT_SPLIT[0]) {
        //     split[0]  
        if (splitLen > 1) {
          if (i + splitLen < dataLen) {
            //     data   
            for (int j = 1; j < splitLen; j++) {
              if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
                break;
              }
              if (j == splitLen - 1) {
                //    split     ,   break,        split 
                isMatchSplit = true;
              }
            }
          }
        } else {
          // split    ,      
          isMatchSplit = true;
        }
      }
      if (isMatchSplit) {
        byte[] part = new byte[i - latestStartIndex];
        System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
        byte[] decryptPart = decryptByPrivateKey(part, privateKey);
        for (byte b : decryptPart) {
          allBytes.add(b);
        }
        latestStartIndex = i + splitLen;
        i = latestStartIndex - 1;
      }
    }
    byte[] bytes = new byte[allBytes.size()];
    {
      int i = 0;
      for (Byte b : allBytes) {
        bytes[i++] = b.byteValue();
      }
    }
    return bytes;
  }
이렇게 해서 만 나 는 문 제 를 해결 했다.프로젝트 에서 사용 하 는 방안 은 클 라 이언 트 공개 키 암호 화,서버 비밀 키 복호화 이다.서버 개발 자 는 효율 적 인 고려 에서 나 온 것 이 라 고 해서 스스로 프로그램 을 써 서 진정한 효율 을 테스트 했다.
STEP 1:대상 데이터 100 개 준비

    List<Person> personList=new ArrayList<>();
    int testMaxCount=100;//         
    //      
    for(int i=0;i<testMaxCount;i++){
      Person person =new Person();
      person.setAge(i);
      person.setName(String.valueOf(i));
      personList.add(person);
    }
    //FastJson  json  

    String jsonData=JsonUtils.objectToJsonForFastJson(personList);

    Log.e("MainActivity","   json   ---->"+jsonData);
    Log.e("MainActivity","   json     ---->"+jsonData.length());
두 번 째 단계 비밀 키 쌍 생 성

    KeyPair keyPair=RSAUtils.generateRSAKeyPair(RSAUtils.DEFAULT_KEY_SIZE);
    //   
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    //   
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
                           

    //    
    long start=System.currentTimeMillis();
    byte[] encryptBytes=  RSAUtils.encryptByPublicKeyForSpilt(jsonData.getBytes(),publicKey.getEncoded());
    long end=System.currentTimeMillis();
    Log.e("MainActivity","       cost time---->"+(end-start));
    String encryStr=Base64Encoder.encode(encryptBytes);
    Log.e("MainActivity","   json   --1-->"+encryStr);
    Log.e("MainActivity","   json     --1-->"+encryStr.length());
    //    
    start=System.currentTimeMillis();
    byte[] decryptBytes= RSAUtils.decryptByPrivateKeyForSpilt(Base64Decoder.decodeToBytes(encryStr),privateKey.getEncoded());
    String decryStr=new String(decryptBytes);
    end=System.currentTimeMillis();
    Log.e("MainActivity","       cost time---->"+(end-start));
    Log.e("MainActivity","   json   --1-->"+decryStr);

    //    
    start=System.currentTimeMillis();
    encryptBytes=  RSAUtils.encryptByPrivateKeyForSpilt(jsonData.getBytes(),privateKey.getEncoded());
    end=System.currentTimeMillis();
    Log.e("MainActivity","        cost time---->"+(end-start));
    encryStr=Base64Encoder.encode(encryptBytes);
    Log.e("MainActivity","   json   --2-->"+encryStr);
    Log.e("MainActivity","   json     --2-->"+encryStr.length());
    //    
    start=System.currentTimeMillis();
    decryptBytes= RSAUtils.decryptByPublicKeyForSpilt(Base64Decoder.decodeToBytes(encryStr),publicKey.getEncoded());
    decryStr=new String(decryptBytes);
    end=System.currentTimeMillis();
    Log.e("MainActivity","       cost time---->"+(end-start));
    Log.e("MainActivity","   json   --2-->"+decryStr);
실행 결과:

비교 결과:비밀 키 의 복호화 에 시간 이 많이 걸 리 기 때문에 서로 다른 수요 에 따라 복호화 할 수 없 는 방안 을 사용 할 수 있 습 니 다.개인 적 으로 서버 의 복호화 효율 이 높 고 클 라 이언 트 의 비밀 키 암호 화,서버 의 공개 키 복호화 가 좋 습 니 다.
암호 화 된 데이터 크기 의 변화:데이터 양 차 는 암호 화 전의 1.5 배 에 달 하지 않 습 니 다.

총결산
이상 은 안 드 로 이 드 Rsa 데이터 복호화 에 관 한 모든 내용 입 니 다.이 글 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 댓 글 을 남 겨 주 십시오.

좋은 웹페이지 즐겨찾기