Я не буду рассматривать хранение 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;

    }

Last edited Jul 5, 2010 at 3:39 AM by gouranga, version 2

Comments

No comments yet.