Android 데이터 암호 화 Rsa 암호 화

선언:
최근 에 동료 들 과 데이터 안전 전송 문 제 를 교류 할 의사 가 없 었 습 니 다.자신 이 사 용 했 던 Rsa 비대 칭 암호 화 알고리즘 을 떠 올 리 고 한가 로 이 정리 해 보 세 요. 
기타 몇 가지 암호 화 방식:
 •Android 데이터 암호 화 Rsa 암호 화
 •Android 데이터 암호 화 Aes 암호 화
 •Android 데이터 암호 화 Des 암호 화
 •Android 데이터 암호 화 MD5 암호 화
 •Android 데이터 암호 화 Base 64 인 코딩 알고리즘
 •Android 데이터 암호 화 SHA 보안 해시 알고리즘 
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   
  *
  * @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 복호화 를 실현 할 수 있 을 것 이 라 고 생각 했 습 니 다.만사 가 다 잘 될 것 이 라 고 생각 했 습 니 다.하하,이 일 은 아직 끝나 지 않 았 습 니 다.비극 이 발생 했 습 니 다.Android 쪽 에서 암호 화 된 데 이 터 는 서버 측 에서 필사적으로 복호화 할 수 없습니다.원래 안 드 로 이 드 시스템 의 RSA 는'RSA/NO/NoPadding'이 고 표준 JDK 실현 은'RSA/NO/PKCS 1 Padding'입 니 다.이것 은 안 드 로 이 드 기기 에서 암호 화 된 후 서버 에서 복호화 할 수 없 는 원인 을 초래 하 였 으 므 로 이 를 실현 할 때 반드시 주의해 야 합 니 다. 
세그먼트 암호 화 실현:충전 방식 을 해결 한 후에 만사 가 다 잘 되 었 다 고 자신 합 니 다.그러나 의외 의 일이 발생 했 습 니 다.RSA 비대 칭 암호 화 내용 의 길이 가 제한 되 어 있 습 니 다.1024 비트 key 의 최대 127 비트 데이터 만 암호 화 할 수 있 습 니 다.그렇지 않 으 면 오류 가 발생 할 수 있 습 니 다(javax.crypto.IllegalBlock Size Exception:Data must not 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 배 에 달 하지 않 습 니 다.

 이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기