Android 데이터 암호 화 Rsa 암호 화의 간단 한 구현

16828 단어 androidrsa암호 화
최근 에 동료 들 과 데이터 안전 전송 문 제 를 교류 할 의사 가 없 었 습 니 다.자신 이 사 용 했 던 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   
   *
   * @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 배 에 달 하지 않 습 니 다.

이상 은 여러분 에 게 안 드 로 이 드 데이터 암호 화의 Rsa 암호 화의 간단 한 실현 모든 내용 입 니 다.많은 응원 부탁드립니다~

좋은 웹페이지 즐겨찾기