/// <param name="data"></param> /// <param name="cryptoKey"></param> /// <param name="IVec"></param> /// <exception cref="UnsupportedEncodingException"></exception> /// <returns></returns> public static byte[] decryptData(byte[] data, byte[] cryptoKey, byte[] IVec) { return(AESHelper.decryptData(data, cryptoKey, IVec, true)); // true =^ PKCS7 padding }
public static byte[] DecryptFile( string encryptedFilePath, byte[] fileCryptoKey, string baseIVec, int blockSize, int offset, int padding) { Console.WriteLine($"AES Decryption of file '{encryptedFilePath}' started"); if (fileCryptoKey.Length <= 0 || blockSize <= 0) { throw new Exception("Crypto key for file can't be empty and block size must be bigger than zero"); } // read the encrypted file byte[] fileBytes; try { fileBytes = File.ReadAllBytes(Path.GetFullPath(encryptedFilePath)); } catch (IOException e) { throw new Exception("Could not read file", e); } // IVec in file header is base 64 encoded byte[] decodedFileIV = Base64Helper.decode(baseIVec); // report initial status int fileSize = fileBytes.Length; long fileSizeFivePer = Convert.ToInt64(Math.Floor(fileSize * 0.05)); // 5% of file size; for status reporting string byteProgress = $" (0 / {fileSize} bytes)"; StringBuilder routeString = new StringBuilder(); StringBuilder spaceString = new StringBuilder(); for (int i = 0; i < 20; i++) { spaceString.Append(" "); } Console.WriteLine($"Progress: [{spaceString}]{byteProgress}"); // decrypt each block separately with its own initialization vector int blockNo = 0; byte[] result = new byte[fileSize - offset - padding]; for (int byteNo = offset, nextStatusThreshold = offset, currentStep = 0; byteNo <= fileSize; byteNo += blockSize, ++blockNo) { byte[] blockIVec = AESHelper.ComputeBlockIVec(decodedFileIV, blockNo, fileCryptoKey); // get the input data for the current block (the last block may be shorter than [blockSize] bytes) int end = (byteNo + blockSize >= fileSize) ? fileSize : byteNo + blockSize; byte[] blockInput = new byte[end - byteNo]; BlockCopy(fileBytes, byteNo, blockInput, 0, end - byteNo); PaddingMode currentPadding = (end == fileSize && padding > 0) ? PaddingMode.PKCS7 : PaddingMode.None; // get the decrypted data for this block ... byte[] decryptedBlock = AESHelper.DecryptData(blockInput, fileCryptoKey, blockIVec, true, currentPadding); // ... and append it to the previous data BlockCopy(decryptedBlock, 0, result, byteNo - offset, decryptedBlock.Length); // report intermediate status every 5% if (byteNo > nextStatusThreshold) { int steps = byteNo / nextStatusThreshold; nextStatusThreshold += Convert.ToInt32(fileSizeFivePer * steps); currentStep += steps; byteProgress = $" ({byteNo} / {fileSize} bytes)"; routeString.Length = 0; for (int i = 0; i < currentStep; i++) { routeString.Append("#"); } spaceString.Length = 0; for (int i = 0; i < 20 - currentStep; i++) { spaceString.Append(" "); } Console.WriteLine($"Progress: [{routeString}{spaceString}]{byteProgress}"); } } // newline after Status report byteProgress = $" ({fileSize} / {fileSize} bytes)"; routeString.Length = 0; for (int i = 0; i < 20; i++) { routeString.Append("#"); } Console.WriteLine($"Progress: [{routeString}]{byteProgress}"); Console.WriteLine("AES decryption of file finished"); return(result); }
/// <exception cref="UnsupportedEncodingException"></exception> public static byte[] decryptFile( string encryptedFilePath, byte[] fileCryptoKey, string baseIVec, int blockSize, int offset, int padding) { Console.WriteLine("AES Decryption of file '" + encryptedFilePath + "' started"); if (fileCryptoKey.Length <= 0 || blockSize <= 0) { throw new SystemException("Crypto key for file can't be empty and block size must be bigger than zero"); } // read the encrypted file byte[] fileBytes; try { fileBytes = File.ReadAllBytes(Path.GetFullPath(encryptedFilePath)); } catch (IOException e) { throw new SystemException("Could not read file", e); } // IVec in file header is base 64 encoded byte[] decodedFileIV = Base64Helper.decode(baseIVec); // report initial status int fileSize = fileBytes.Length; long fileSizeFivePer = Convert.ToInt64(Math.Floor(fileSize * 0.05)); // 5% of file size; for status reporting string byteProgress = " (0 / " + fileSize + " bytes)"; StringBuilder routeString = new StringBuilder(); StringBuilder spaceString = new StringBuilder(); for (int i = 0; i < 20; i++) { spaceString.Append(" "); } Console.WriteLine("Progress: [{0}]{1}", spaceString, byteProgress); // decrypt each block separately with its own initialization vector int blockNo = 0; byte[] result = new byte[fileSize - offset - padding]; for (int byteNo = offset, nextStatusThreshold = offset, currentStep = 0; byteNo <= fileSize; byteNo += blockSize, ++blockNo) { byte[] blockIVec = AESHelper.computeBlockIVec(decodedFileIV, blockNo, fileCryptoKey); // get the input data for the current block (the last block may be shorter than [blockSize] bytes) int end = (byteNo + blockSize >= fileSize) ? fileSize : byteNo + blockSize; byte[] blockInput = new byte[end - byteNo]; System.Buffer.BlockCopy(fileBytes, byteNo, blockInput, 0, end - byteNo); // PKCS7 padding for the last block if a cipher padding size greater than 0 was specified in file header // Note: the only differnce between PKCS5 and 7 is the block size (8 and 0-255 bytes respectively), // Java only offers the 'PKCS5PADDING' identifier (legacy from the time only 8 byte block ciphers were available) bool currentPadding = (end == fileSize && padding > 0) ? true : false; // get the decrypted data for this block ... byte[] decryptedBlock = AESHelper.decryptData(blockInput, fileCryptoKey, blockIVec, currentPadding); // ... and append it to the previous data System.Buffer.BlockCopy(decryptedBlock, 0, result, byteNo - offset, decryptedBlock.Length); // report intermediate status every 5% if (byteNo > nextStatusThreshold) { int steps = byteNo / nextStatusThreshold; nextStatusThreshold += Convert.ToInt32(fileSizeFivePer * steps); currentStep += steps; byteProgress = " (" + byteNo + " / " + fileSize + " bytes)"; routeString.Length = 0; for (int i = 0; i < currentStep; i++) { routeString.Append("#"); } spaceString.Length = 0; for (int i = 0; i < 20 - currentStep; i++) { spaceString.Append(" "); } Console.WriteLine("Progress: [{0}{1}]{2}", routeString, spaceString, byteProgress); } } // newline after Status report byteProgress = " (" + fileSize + " / " + fileSize + " bytes)"; routeString.Length = 0; for (int i = 0; i < 20; i++) { routeString.Append("#"); } Console.WriteLine("Progress: [{0}]{1}", routeString, byteProgress); Console.WriteLine("AES decryption of file finished"); return(result); }
static void Main(string[] args) { if (args.Length < 3) { Console.WriteLine("Usage: bc-file-decryptor \n" + "[path to .bckey file] " + "[path to encrypted file] " + "[pwd] " + "[path for output (optional)]"); return; } try { Console.WriteLine("Decryption process started"); // ============================================ // AES decryption of private key in .bckey file // ============================================= // collect information about the user account AccountData accountInfo = new AccountData(); accountInfo.ParseBCKeyFile(args[0]); accountInfo.Password = args[2]; // decrypt the private key from the .bckey file byte[] decryptedPrivateKey = AESHelper.DecryptDataPBKDF2( accountInfo.EncryptedPrivateKey, accountInfo.Password, accountInfo.PBKDF2Salt, accountInfo.PBKDF2Iterations ); // ============================================= // RSA decryption of file information (header) // ============================================= // collect information about the file to be decrypted FileData fileData = new FileData(); string outputFilePath = args.Length > 3 ? args[3] : ""; fileData.ParseHeader(args[1], outputFilePath); // decrypt the file key (from the header) used for decryption of file data byte[] decryptedFileKey = RSAHelper.DecryptData(fileData.EncryptedFileKey, decryptedPrivateKey); byte[] fileCryptoKey = new byte[32]; BlockCopy(decryptedFileKey, 32, fileCryptoKey, 0, 32); // ============================================= // AES decryption of encrypted file // ============================================= // decrypt the file data ... byte[] decryptedFileBytes = AESHelper.DecryptFile( fileData.EncryptedFilePath, fileCryptoKey, fileData.BaseIVec, fileData.BlockSize, fileData.HeaderLen, fileData.CipherPadding); File.WriteAllBytes(Path.GetFullPath(fileData.OutputFilePath), decryptedFileBytes); Console.WriteLine($"Successfully decrypted file '{fileData.EncryptedFilePath}', " + $"output: '{fileData.OutputFilePath}'"); } catch (Exception e) { Console.WriteLine(e.Message); if (e.StackTrace != null) { Console.WriteLine(e.StackTrace); } } }