如何使用OpenSSL :: Cipher加密固定大小的数字

时间:2016-05-29 04:58:07

标签: ruby encryption encoding openssl

我需要使用OpenSSL::Cipher::AES加密一个数字,但是我很难理解我需要用什么组合来获得已知结果。

我有以下Java参考代码:

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import com.google.common.primitives.Longs;

class Encryptor {
  private String initialVector;
  private static final String TRANFORMATION = "AES/CBC/PKCS5Padding";
  private static final String ALGORITHM = "AES";

  String encrypt(SecretKeySpec key, long timestamp) throws Exception {
    byte[] encryptedBytes = getEncryptingCipher(key).doFinal(Longs.toByteArray(timestamp));
    return Base64.encodeBase64String(encryptedBytes);
  }

  private Cipher getEncryptingCipher(SecretKeySpec key) throws
    NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException,
    InvalidKeyException,
    InvalidAlgorithmParameterException {
      Cipher encryptingCipher = Cipher.getInstance(TRANFORMATION);
      encryptingCipher.init(Cipher.ENCRYPT_MODE, key, new
          IvParameterSpec(initialVector.getBytes()));
      return encryptingCipher;
  }

  private SecretKeySpec getSecretKeySpec(String key) throws DecoderException {
    byte[] keyBytes = Hex.decodeHex(key.toCharArray());
    return new SecretKeySpec(keyBytes, ALGORITHM);
  }

  void setInitialVector(String initialVector) {
    this.initialVector = initialVector;
  }

  public static void main(String[] args) throws Exception {
    Encryptor encryptor = new Encryptor();
    encryptor.setInitialVector("0000000000000000");
    //Expensive operation so only performed once, re-use the key spec instance
    SecretKeySpec keySpec =
    encryptor.getSecretKeySpec("b35901b480ca658c8be4341eefe21a80");
    long timestamp = 1464284796L; //System.currentTimeMillis() / 1000;
    String authToken = encryptor.encrypt(keySpec, timestamp);
    System.out.println(authToken);
  }
}

这导致在控制台上打印以下base64编码字符串:6BH3hg1cqQJOK6sG8gw7Xw==

我试图用OpenSSL::Cipher复制这个,但我没有运气。 Ruby OpenSSL文档缺乏细节。我怀疑我对包的使用是不正确的。

require "openssl"

key = ['b35901b480ca658c8be4341eefe21a80'].pack('H*')
iv  = '0000000000000000'
message = [1464284796].pack "N*"

cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.encrypt

cipher.iv  = iv
cipher.key = key

encrypted = cipher.update(message)
encrypted << cipher.final

cipher64 = [encrypted].pack('m')

puts "Generated: " + cipher64
puts "Expected : " + '6BH3hg1cqQJOK6sG8gw7Xw=='

1 个答案:

答案 0 :(得分:2)

Guava文档说明Longs#toByteArray(long)

  

toByteArray(long value)
  返回8个元素字节数组中value的大端表示形式;相当于ByteBuffer.allocate(8).putLong(value).array()

但Ruby Array#pack "N*"对32位无符号整数进行编码,产生4个字节。所以,你可以简单地用4个零填充它:

message = [0, 1464284796].pack "N*"
使用big-endian 64位整数的注释中的

matt注释:

message = [1464284796].pack "Q>"