diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..575a1af --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +target/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d607768..5dda89c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,23 +265,6 @@ name = "hex" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "hex-literal" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "http" version = "0.2.1" @@ -584,11 +567,6 @@ name = "ppv-lite86" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "proc-macro-hack" -version = "0.5.16" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc-macro2" version = "1.0.18" @@ -696,7 +674,6 @@ dependencies = [ "base64 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "block-modes 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1113,8 +1090,6 @@ dependencies = [ "checksum h2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "79b7246d7e4b979c03fa093da39cfb3617a96bbeee6310af63991668d7e843ff" "checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -"checksum hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -"checksum hex-literal-impl 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" "checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" "checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" @@ -1151,7 +1126,6 @@ dependencies = [ "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" "checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" "checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" diff --git a/Cargo.toml b/Cargo.toml index fbda261..a4b7a3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ aes-soft = "0.4.0" base64 = "0.12.1" block-modes = "0.4.0" hex = "0.4.2" -hex-literal = "0.2.1" http = "0.2.1" libc = "0.2.71" reqwest = { version = "0.10.6", features = ["blocking"] } diff --git a/README.md b/README.md index 296bfaf..60fe712 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -### Build 32-bit +## Installation + +### Build 32-bit .dll ``` cargo build --target=i686-pc-windows-msvc --release @@ -7,7 +9,7 @@ cargo build --target=i686-pc-windows-msvc --release Output file: `.\target\i686-pc-windows-msvc\release\rhttp.dll` -### Build 64-bit +### Build 64-bit .dll ``` cargo build --target=x86_64-pc-windows-msvc --release @@ -15,28 +17,67 @@ cargo build --target=x86_64-pc-windows-msvc --release Output file: `.\target\x86_64-pc-windows-msvc\release\rhttp.dll` -### Test via python 3 +## Test via python 3 ``` > python3 .\test.py --dll .\target\x86_64-pc-windows-msvc\release\rhttp.dll -16 -2.25 -6.25 -5 -Szia, Apu! -aaaaa -ő na na na na na Batman! ő -(True, 'YW55IGNhcm5hbCBwbGVhc3VyZS4=', 'any carnal pleasure.') -(True, '7b6f7690ae2a5ecdf66b3db2adf91340a680da1ab82561796b8504db942476967369814aa35050dd86838848c1ba703450f2f5e21b0a8e4cff690b855ae5bd8c', '7b6f7690ae2a5ecdf66b3db2adf91340a680da1ab82561796b8504db942476967369814aa35050dd86838848c1ba703450f2f5e21b0a8e4cff690b855ae5bd8c') -(True, 'ef846feafed891792553756277b48e90784eca281f683920551f36b359833b10aab4897765050e398232e3f213fe49c7c50271f339d4797c25dc58c3d7f33f81', 'ef846feafed891792553756277b48e90784eca281f683920551f36b359833b10aab4897765050e398232e3f213fe49c7c50271f339d4797c25dc58c3d7f33f81') +True +True +True +OK +True +True +``` + +## Methods + +### Base64 encode and decode + +```rust +fn base64_decode(s: *const c_char) -> *mut c_char {} +fn base64_encode(s: *const c_char) -> *mut c_char {} ``` -### VFP notes +### Hashing via SHA-512 +```rust +fn sha512_hash(s: *const c_char) -> *mut c_char {} ``` -DECLARE sha3_512_encode "rhttp.dll" @STRING, @STRING -testString = "TestVFP" -sha512_encode(0, @testString ) +### Hashing via SHA3-512 + +```rust +fn sha3_512_hash(s: *const c_char) -> *mut c_char {} +``` + +### AES encrypt and decrypt + +`aes_encrypt` and `aes_decrypt` are used to encrypt and decrypt messages via using [AES-128](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) block cipher in [ECB mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_(ECB)) and with [PKCS#7 padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS#5_and_PKCS#7). + +Both method works primarily on byte arrays which you can provide as `plain text`, `hexadecimal representation` and `base64 encoding`. These can be configured by setting the plans as designed: -``` \ No newline at end of file +Flags can be provided as a 32-bit integer (for compatibility reasons), which then will be converted into an unsigned integer. These flags can be combined, but some combinations will be ignored: +- 0x01 - Input is provided as `hexadecimal representation` +- 0x02 - Input is provided using `base64 encoding` +- 0x04 - Output should be returned in a `hexadecimal representation` +- 0x08 - Output should be returned using `base64 encoding` +- 0x10 - Key is provided as `hexadecimal representation` +- 0x20 - Key is provided using `base64 encoding` + +```rust +fn aes_encrypt(c_plaintext: *const c_char, c_key: *const c_char, flags: i32) -> *mut c_char {} + +fn aes_decrypt(c_ciphertext: *const c_char, c_key: *const c_char, flags: i32) -> *mut c_char {} +``` + +### HTTP(s) GET + +```rust +fn get(c_url: *const c_char) -> *mut c_char +``` + +### HTTP(s) POST with XML headers + +```rust +fn post_xml(c_url: *const c_char, c_body: *const c_char) -> *mut c_char +``` diff --git a/src/lib.rs b/src/lib.rs index b4d3abd..c2103a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,13 +6,11 @@ extern crate sha3; extern crate reqwest; extern crate aes_soft as aes; extern crate block_modes; -extern crate hex_literal; //external crates use aes::Aes128; -use block_modes::{BlockMode, Cbc}; +use block_modes::{BlockMode, Ecb}; use block_modes::block_padding::Pkcs7; -use hex_literal::hex; use http::HeaderMap; use http::header::{CONTENT_TYPE, ACCEPT}; use libc::c_char; @@ -21,25 +19,7 @@ use sha2::{Sha512, Digest}; use sha3::{Sha3_512}; use std::ffi::CString; use std::ffi::CStr; - -// create an alias for convinience -type Aes128Cbc = Cbc; - -fn c_str_ptr_to_rust(s: *const c_char) -> &'static str { - let c_str = unsafe { - assert!(!s.is_null()); - - CStr::from_ptr(s) - }; - - return c_str.to_str().unwrap(); -} - -fn rust_to_c_str_ptr(s: String) -> *mut c_char { - let c_str = CString::new(s).unwrap(); - - return c_str.into_raw() -} +use std::str; #[no_mangle] pub extern "C" fn free_string(s: *mut c_char) { @@ -73,7 +53,7 @@ pub extern "C" fn base64_decode(s: *const c_char) -> *mut c_char { } #[no_mangle] -pub extern "C" fn sha512_encode(s: *const c_char) -> *mut c_char { +pub extern "C" fn sha512_hash(s: *const c_char) -> *mut c_char { let r_str = c_str_ptr_to_rust(s); let mut hasher = Sha512::new(); @@ -86,7 +66,7 @@ pub extern "C" fn sha512_encode(s: *const c_char) -> *mut c_char { } #[no_mangle] -pub extern "C" fn sha3_512_encode(s: *const c_char) -> *mut c_char { +pub extern "C" fn sha3_512_hash(s: *const c_char) -> *mut c_char { let r_str = c_str_ptr_to_rust(s); let mut hasher = Sha3_512::new(); @@ -99,28 +79,25 @@ pub extern "C" fn sha3_512_encode(s: *const c_char) -> *mut c_char { } #[no_mangle] -pub extern "C" fn aes_encode() -> *mut c_char { - let key = hex!("000102030405060708090a0b0c0d0e0f"); - let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); - let plaintext = b"Hello world!"; - let cipher = Aes128Cbc::new_var(&key, &iv).unwrap(); - - let ciphertext = cipher.encrypt_vec(plaintext); - - return rust_to_c_str_ptr(hex::encode(ciphertext)); +pub extern "C" fn aes_encrypt(c_plaintext: *const c_char, c_key: *const c_char, flags: i32) -> *mut c_char { + let uflags = flags as u32; + let input = decode_c(c_plaintext, uflags); + let key = decode_c(c_key, uflags >> 4); + + let ciphertext = create_cipher(key).encrypt_vec(input.as_slice()); + + return rust_to_c_str_ptr(encode_c(ciphertext, uflags >> 2)); } -// #[no_mangle] -pub extern "C" fn aes_decode() -> *mut c_char { - let ciphertext = hex!("1b7a4c403124ae2fb52bedc534d82fa8"); - - let key = hex!("000102030405060708090a0b0c0d0e0f"); - let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); - let cipher = Aes128Cbc::new_var(&key, &iv).unwrap(); +#[no_mangle] +pub extern "C" fn aes_decrypt(c_ciphertext: *const c_char, c_key: *const c_char, flags: i32) -> *mut c_char { + let uflags = flags as u32; + let input = decode_c(c_ciphertext, uflags); + let key = decode_c(c_key, uflags >> 4); - let decrypted_ciphertext = cipher.decrypt_vec(&ciphertext).unwrap(); + let plaintext = create_cipher(key).decrypt_vec(input.as_slice()).unwrap(); - return rust_to_c_str_ptr(hex::encode(decrypted_ciphertext)); + return rust_to_c_str_ptr(encode_c(plaintext, uflags >> 2)); } #[no_mangle] @@ -172,3 +149,51 @@ pub extern "C" fn post_xml(c_url: *const c_char, c_body: *const c_char) -> *mut return rust_to_c_str_ptr(body); } + +fn decode_c(c_input: *const c_char, flags: u32) -> Vec { + let input = c_str_ptr_to_rust(c_input); + + if flags % 2 == 1 { + return hex::decode(input).unwrap(); + } + + if (flags >> 1) % 2 == 1 { + return base64::decode_config(input, base64::STANDARD).unwrap(); + } + + return String::from(input).into_bytes(); +} + +fn encode_c(raw: Vec, flags: u32) -> String { + if flags % 2 == 1 { + return hex::encode(raw); + } + + if (flags >> 1) % 2 == 1 { + return base64::encode_config(raw, base64::STANDARD); + } + + return String::from_utf8(raw).unwrap(); +} + +fn create_cipher(key: Vec) -> Ecb:: { + let iv = Default::default(); + + return Ecb::::new_var(key.as_slice(), iv).unwrap(); +} + +fn c_str_ptr_to_rust(s: *const c_char) -> &'static str { + let c_str = unsafe { + assert!(!s.is_null()); + + CStr::from_ptr(s) + }; + + return c_str.to_str().unwrap(); +} + +fn rust_to_c_str_ptr(s: String) -> *mut c_char { + let c_str = CString::new(s).unwrap(); + + return c_str.into_raw() +} \ No newline at end of file diff --git a/test.py b/test.py index 1064680..77a95e6 100644 --- a/test.py +++ b/test.py @@ -19,11 +19,11 @@ lib.base64_decode.argtypes = (c_void_p, ) lib.base64_decode.restype = c_void_p -lib.sha512_encode.argtypes = (c_void_p, ) -lib.sha512_encode.restype = c_void_p +lib.sha512_hash.argtypes = (c_void_p, ) +lib.sha512_hash.restype = c_void_p -lib.sha3_512_encode.argtypes = (c_void_p, ) -lib.sha3_512_encode.restype = c_void_p +lib.sha3_512_hash.argtypes = (c_void_p, ) +lib.sha3_512_hash.restype = c_void_p lib.get.argtypes = (c_void_p, ) lib.get.restype = c_void_p @@ -31,6 +31,12 @@ lib.post_xml.argtypes = (c_void_p, c_void_p, ) lib.post_xml.restype = c_void_p +lib.aes_encrypt.argtypes = (c_void_p, c_void_p, c_int32, ) +lib.aes_encrypt.restype = c_void_p + +lib.aes_decrypt.argtypes = (c_void_p, c_void_p, c_int32, ) +lib.aes_decrypt.restype = c_void_p + def base64(text): ptr1 = lib.base64_encode(text.encode('utf-8')) try: @@ -48,7 +54,7 @@ def base64(text): lib.free_string(ptr1) def sha512(text, expected): - ptr1 = lib.sha512_encode(text.encode('utf-8')) + ptr1 = lib.sha512_hash(text.encode('utf-8')) try: hashed = ctypes.cast(ptr1, ctypes.c_char_p).value.decode('utf-8') if hashed == expected: @@ -59,7 +65,7 @@ def sha512(text, expected): lib.free_string(ptr1) def sha3_512(text, expected): - ptr1 = lib.sha3_512_encode(text.encode('utf-8')) + ptr1 = lib.sha3_512_hash(text.encode('utf-8')) try: hashed = ctypes.cast(ptr1, ctypes.c_char_p).value.decode('utf-8') if hashed == expected: @@ -78,7 +84,7 @@ def get(url): finally: lib.free_string(ptr1) -def postXml(url, body): +def post_xml(url, body): ptr1 = lib.post_xml(url.encode('utf-8'), body.encode('utf-8')) try: response = ctypes.cast(ptr1, ctypes.c_char_p).value.decode('utf-8') @@ -87,36 +93,39 @@ def postXml(url, body): finally: lib.free_string(ptr1) -tokenUrl = "https://api-test.onlineszamla.nav.gov.hu/invoiceService/tokenExchange" -tokenPayload = """ - -
- RID896801578348 - 2019-09-11T10:55:31.440Z - 2.0 - 1.0 -
- - lwilsmn0uqdxe6u - 2F43840A882CFDB7DB0FEC07D419D030D864B47B6B541DC280EF81B937B7A176E33C052B0D26638CC18A7A2C08D8D311733078A774BF43F6CA57FE8CD74DC28E - 11111111 - B4B5E0F197BFFD3DF69BCC98D3BE775F65FD5445EEF95C9D6B6C59425F2B81C4F6DA1FD563B0C7E7D98AF1E1725E5C63C2803B5D3A93D1C02ED354AC92F2CC94 - - - - 123456789123456789 - string - LOCAL_SOFTWARE - string - string - string - HU - string - -
""" - -print(base64("any carnal pleasure.")) +def aes_encrypt(plaintext, key, flags, expected): + ptr1 = lib.aes_encrypt(plaintext.encode('utf-8'), key.encode('utf-8'), flags) + try: + response = ctypes.cast(ptr1, ctypes.c_char_p).value.decode('utf-8') + if response == expected: + return True + + return response + finally: + lib.free_string(ptr1) + +def aes_decrypt(ciphertext, key, flags, expected): + ptr1 = lib.aes_decrypt(ciphertext.encode('utf-8'), key.encode('utf-8'), flags) + try: + response = ctypes.cast(ptr1, ctypes.c_char_p).value.decode('utf-8') + if response == expected: + return True + + return response + finally: + lib.free_string(ptr1) + +print(base64('Vényítés hehez egyébként bodta, hogy a redés abban a pánságban havóval vátszik, amikor végre tapolyhoz irdíti majd a tűnőségöket. A rémetleg robákban a kató főzés hompai által a zsintőnél pidő hűsítő birt olyan kamatokat logazott fel, amelyek súlyosan szaborázják a zsintő bormogtatos rozásait. Ennek megfelelően az ömlés hompai a kanyós felebelő manákat és kirderedéseket a hályogó talányozott pachok felé kozatosék. 1 csengyedemer húzatás, 2 feke lenemek, 1 pikkely trozás, nészer, 1 vice párom, 4 vice haság, 1 ratyi melelő.')) print(sha512("mysecret", "7b6f7690ae2a5ecdf66b3db2adf91340a680da1ab82561796b8504db942476967369814aa35050dd86838848c1ba703450f2f5e21b0a8e4cff690b855ae5bd8c")) print(sha3_512("mysecret", "ef846feafed891792553756277b48e90784eca281f683920551f36b359833b10aab4897765050e398232e3f213fe49c7c50271f339d4797c25dc58c3d7f33f81")) print(get("https://api-test.onlineszamla.nav.gov.hu/")) -print(postXml(tokenUrl, tokenPayload)) + +# input: plain -> 0000 0000 +# output: base64 -> 0000 1000 +# key: hex -> 0001 0000 +print(aes_encrypt("hello", "000102030405060708090a0b0c0d0e0f", 0x18, 'XYdJ4q91MbK/ZmHp5drwEg==')) + +# input: base64 -> 0000 0010 +# output: plain -> 0000 0000 +# key: hex -> 0001 0000 +print(aes_decrypt("XYdJ4q91MbK/ZmHp5drwEg==", "000102030405060708090a0b0c0d0e0f", 0x12, 'hello')) \ No newline at end of file