Я не буду рассматривать хранение rsa ключей. Исключительно алгоритмы упаковки и подписи файлов. Организация всего остального — дело техники.
Упаковка на Java
public void doPakage(File fileInput, File fileOutput) throws FileNotFoundException, IOException {
// создадим новый файл, должно просто стереть старый.
fileOutput.createNewFile();
InputStream fileInputStream = new FileInputStream(fileInput);
OutputStream fileOutputStream = new FileOutputStream(fileOutput);
byte[] buffer = new byte[(int)fileInput.length()];
byte[] buffer2 = new byte[(int)fileInput.length()];
ByteBuffer temp = ByteBuffer.allocate(4);
temp.order(ByteOrder.LITTLE_ENDIAN);
temp.putInt((int)fileInput.length());
int compressedDataLength = (int)fileInput.length();
fileInputStream.read(buffer);
// упаковка файла
Deflater compresser = new Deflater(Deflater.BEST_SPEED,false);
compresser.setInput(buffer);
compresser.finish();
compressedDataLength = compresser.deflate(buffer2);
if(fileInput.length() <= compressedDataLength)
buffer2 = buffer;
fileOutputStream.write(temp.array());
fileOutputStream.write(buffer2, 0, compressedDataLength);
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
}
Подпись файла на Java
private PrivateKey privateKey; // приватный ключ
private PublicKey publicKey; // паблик ключ
private BigInteger modus; // сюда мы подгрузим ключи, чтобы не приходилось каждый раз генерировать
private BigInteger privateX;
private BigInteger publicX;
/**
* Надпись перед подписью.
*/
public String signatereText = "-----BEGIN ELEMENT SIGNATURE-----\n";
/**
* Генерация ключей.
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchProviderException
*/
private void doGenerate() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
KeyPair pair = keyGen.generateKeyPair();
privateKey = pair.getPrivate();
publicKey = pair.getPublic();
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec prks = kf.getKeySpec(privateKey, RSAPrivateKeySpec.class);
modus = prks.getModulus();
privateX = prks.getPrivateExponent();
RSAPublicKeySpec pubks = kf.getKeySpec(publicKey, RSAPublicKeySpec.class);
publicX = pubks.getPublicExponent();
}
/**
* Загрузка ключей из входных переменных.
* @param privateXL
* @param publicXL
* @param modusL
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private void doLoad(BigInteger privateXL, BigInteger publicXL, BigInteger modusL) throws NoSuchAlgorithmException, InvalidKeySpecException {
modus = modusL;
privateX = privateXL;
publicX = publicXL;
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec new_prks = new RSAPrivateKeySpec(modus, privateX);
RSAPublicKeySpec new_pubks = new RSAPublicKeySpec(modus, publicX);
privateKey = kf.generatePrivate(new_prks);
publicKey = kf.generatePublic(new_pubks);
}
/**
* Подпись для строки what
* @param what
* @return
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public String doSignature(String what) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
String encryptedText;
byte[] textBytes = what.getBytes();
Signature dsa = Signature.getInstance("MD5withRSA");
dsa.initSign(privateKey);
dsa.update(textBytes);
byte[] encryptedBytes = dsa.sign();
encryptedText = CPWBase64.encodeBytes(encryptedBytes).toString();
return signatereText + encryptedText;
}
/**
* Рассчет подписи файла what и запись этой подписи в конец файла.
* @param what
* @param fos
* @return
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public boolean doSignature(File what, OutputStream fos) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature dsa = Signature.getInstance("MD5withRSA");
dsa.initSign(privateKey);
FileInputStream fis = new FileInputStream(what);
BufferedInputStream bufin = new BufferedInputStream(fis);
byte[] buffer = new byte[1024];
int len;
while(bufin.available() != 0) {
len = bufin.read(buffer);
dsa.update(buffer, 0, len);
}
bufin.close();
fis.close();
byte[] realSig = dsa.sign();
fos.write(signatereText.getBytes());
String signature = CPWBase64.encodeBytes(realSig);
for(int i=0; i<signature.length(); i=i+64) {
int b=i+64;
if(b > signature.length()) b = signature.length();
fos.write(new String(signature.substring(i,b)+"\n").getBytes());
}
return true;
}
Упаковка на C#
Подойдет любая правильная реализация Zlib. См.
Google.
Подпись на C#
// Строки должны быть в utf16-le. Это лучше реализовать с помощью:
UnicodeEncoding ByteConverter = new UnicodeEncoding();
// Сюда вместо «Data to Sign» подсунуть содержимое листа, до фразы -----BEGIN ELEMENT SIGNATURE-----
byte[] dataString = ByteConverter.GetBytes("Data to Sign");
// Сюда запишем подпись.
string signedDataString = "";
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024))
{
// Вот так надо сохранять ключи, т.к. при инициализации RSACryptoServiceProvider сам создает ключи.
// Соответственно, если мы их не сохраним, то в следующий раз придется еще раз патчить patcher.exe b launcher.exe.
// RSA.ToXmlString(true);
// А вот так надо их загружать.
// RSA.FromXmlString(privateKey);
// Подпись в бинарном виде, подписываем алгоритмом MD5.
byte[] signedData = RSA.SignData(dataString, new MD5CryptoServiceProvider());
// Ключ хранится в обычном base64 представлении.
// Здесь он будет записан в одну строку, длинной 172 символа.
// Однако, в файл с листом он должен быть записан блоками по 64 символа. Смотрите метод String.Substring()
signedDataString = Convert.ToBase64String(signedData);
}
Упаковка на php
За код спасибо sh@dow.
class compressor {
public $input; а входе
public $output; - выходе
public $size_unpacked;
public function __construct($input) {
$this->input = $input;
unset($input);
$this->size_unpacked = strlen($this->input);
$this->doPaсkage();
}
public function doPaсkage() {
$compressed = gzcompress($this->input, 9);
$length_string = pack('i', $this->size_unpacked);
$output = $length_string.$compressed;
$this->output = $output;
$this->input = '';
}
}
Подпись на php
private function doSignature() {
openssl_sign ( $this->input, $signature, $this->private_key , OPENSSL_ALGO_MD5 );
$signature = base64_encode($signature);
$signature = wordwrap($signature, 64,"\n", 1);
$this->signature = $signature;
}