I want to write and read a response from USB HID device in Linux using user space library. Googling for a while, I found that libhid will be a solution for the problem.
So, when I used hid_interrupt_write and hid_interrupt_read to send and receive data, this error occurred:
error submitting URB: No such file or directory
But when I tried to use hid_set_output_report and hid_get_input_report to write and read from the device, this error occurred:
error sending control message: Connection timed out.
and
error submitting URB: No such file or directory
and, I am not sure how to get the Usage_Path.
Could anyone help me with this problem? Any suggestions?
Here are my source code and its result when executed:
#include <hid.h>
#include <stdio.h>
#include <string.h>
#define EP_HID_IN 0x81
#define EP_HID_OUT 0x02
#define PACKET_INT_LEN 8
char command[8];
char answer[8];
const int PATHLEN = 2;
int const PATH_IN[2] = { 0xffff0001, 0xffff0003 };
int const PATH_OUT[2] = {0xffff0001, 0xffff0005 };
const int SEND_PACKET_LEN = 8;
const int RECV_PACKET_LEN = 8;
bool match_serial_number(struct usb_dev_handle* usbdev, void* custom, unsigned int len)
{
bool ret;
char* buffer = (char*)malloc(len);
usb_get_string_simple(usbdev, usb_device(usbdev)->descriptor.iSerialNumber,
buffer, len);
ret = strncmp(buffer, (char*)custom, len) == 0;
free(buffer);
return ret;
}
int main(void)
{
HIDInterface* hid;
hid_return ret;
int i = 0;
HIDInterfaceMatcher matcher = { 0x03eb, 0x4b4e, NULL, NULL, 0 };
/* see include/debug.h for possible values */
hid_set_debug(HID_DEBUG_ALL);
hid_set_debug_stream(stderr);
/* passed directly to libusb */
hid_set_usb_debug(1);
ret = hid_init();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_init failed with return code %d\n", ret);
return 1;
}
hid = hid_new_HIDInterface();
if (hid == 0) {
fprintf(stderr, "hid_new_HIDInterface() failed, out of memory?\n");
return 1;
}
ret = hid_force_open(hid, 0, &matcher, 3);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_force_open failed with return code %d\n", ret);
return 1;
}
ret = hid_write_identification(stdout, hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_write_identification failed with return code %d\n", ret);
return 1;
}
ret = hid_dump_tree(stdout, hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_dump_tree failed with return code %d\n", ret);
return 1;
}
// Set command,
command[0] = 0x03;
command[1] = 0x01;
command[2] = 0x31;
command[3] = 0x31;
command[4] = 0x04;
command[5] = 0x00;
command[6] = 0x00;
command[7] = 0x00;
/*
ret = hid_set_output_report(hid, PATH_IN, PATHLEN, command, SEND_PACKET_LEN);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_set_output_report failed with return code %d\n", ret);
}
ret = hid_get_input_report(hid, PATH_OUT, PATHLEN, answer, RECV_PACKET_LEN);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_get_input_report failed with return code %d\n", ret);
}
*/
ret = hid_interrupt_write(hid, EP_HID_OUT, command, PACKET_INT_LEN, 20);
if (ret < 0) {
printf("error in interrupt write\n");
return 1;
}
printf("Reading interrupt\n");
ret = hid_interrupt_read(hid, EP_HID_IN, answer, PACKET_INT_LEN, 4);
if(ret < 0) {
printf("error interrupt read\n");
return 1;
}
printf("Interrupt Transfer Loop Test Result:\n");
for(i = 0;i < PACKET_INT_LEN; i++) {
if(i%8 == 0)
printf("\n");
printf("%02x; ",command[i]);
}
printf("\n");
printf("\n");
for(i = 0;i < PACKET_INT_LEN; i++) {
if(i%8 == 0)
printf("\n");
printf("%02x; ",answer[i]);
}
printf("\n");
printf("\n");
ret = hid_close(hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_close failed with return code %d\n", ret);
return 1;
}
hid_delete_HIDInterface(&hid);
ret = hid_cleanup();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_cleanup failed with return code %d\n", ret);
return 1;
}
return 0;
}
Result:
# ./test_libhid
usb_set_debug: Setting debugging level to 1 (on)
NOTICE: hid_init(): libhid 0.2.15+20060325.0.0 is being initialized.
TRACE: hid_init(): initialising USB subsystem...
usb_os_init: Found USB VFS at /dev/bus/usb
...
...
device identification of HIDInterface 002/009[0]:
dev_handle: 0x09a52098
device: 0x09a55068
location: 002/009
manufacturer: ATMEL
product: Firmware Demo
TRACE: hid_reset_parser(): resetting the HID parser for USB device 002/009[0]...
TRACE: hid_dump_tree(): iterating the parse tree for USB device 002/009[0]...
parse tree of HIDInterface 002/009[0]:
path: 0xffff0001.0xffff0002; type: 0x80
path: 0xffff0001.0xffff0003; type: 0x80
path: 0xffff0001.0x00000000; type: 0x80
path: 0xffff0001.0x00000000; type: 0x80
path: 0xffff0001.0x00000000; type: 0x80
path: 0xffff0001.0x00000000; type: 0x80
path: 0xffff0001.0x00000000; type: 0x80
path: 0xffff0001.0x00000000; type: 0x80
path: 0xffff0001.0xffff0004; type: 0x90
path: 0xffff0001.0xffff0005; type: 0x90
path: 0xffff0001.0x00000000; type: 0x90
path: 0xffff0001.0x00000000; type: 0x90
path: 0xffff0001.0x00000000; type: 0x90
path: 0xffff0001.0x00000000; type: 0x90
path: 0xffff0001.0x00000000; type: 0x90
path: 0xffff0001.0x00000000; type: 0x90
path: 0xffff0001.0xffff0006; type: 0xb0
path: 0xffff0001.0xffff0007; type: 0xb0
path: 0xffff0001.0x00000000; type: 0xb0
path: 0xffff0001.0x00000000; type: 0xb0
TRACE: hid_reset_parser(): resetting the HID parser for USB device 002/009[0]...
TRACE: hid_set_output_report(): looking up report ID...
TRACE: hid_prepare_parse_path(): preparing search path of depth 2 for parse tree of USB device 002/009[0]...
TRACE: hid_prepare_parse_path(): search path prepared for parse tree of USB device 002/009[0].
NOTICE: hid_find_object(): found requested item.
TRACE: hid_set_output_report(): sending report ID 0x00 (length: 8) to USB device 002/009[0]...
WARNING: hid_set_output_report(): failed to send report to USB device 002/009[0]:error sending control message: Connection timed out.
hid_set_output_report failed with return code 19
Reading interrupt
TRACE: hid_interrupt_read(): retrieving interrupt report from device 002/009[0] ...
WARNING: hid_interrupt_read(): failed to get interrupt read from device 002/009[0]: error submitting URB: No such file or directory
Interrupt Transfer Loop Test Result:
03; 01; 31; 31; 04; 00; 00; 00;
00; 00; 00; 00; 00; 00; 00; 00;
TRACE: hid_close(): closing USB device 002/009[0]...
TRACE: hid_close(): closing handle of USB device 002/009[0]...
NOTICE: hid_close(): successfully closed USB device 002/009[0].
TRACE: hid_reset_parser(): resetting the HID parser for USB device 002/009[0]...
TRACE: hid_close(): freeing memory allocated for HID parser...
TRACE: hid_close(): resetting HIDInterface...
NOTICE: hid_cleanup(): successfully deinitialised HID library.
Libhid is built on top of libusb. And honestly, libusb is a much better library. It makes it very easy to communicate back and forth. In fact, if you are interested, I can send you an example program that reads and writes to a HID device.
Libhid requires so much more effort and the documentation is much worse.
Of course either way you have to make sure you're writing to the correct device (by checking product and vendor id) and also sending the correct packets to the correct path if using libhid. (There are three paths: input, output, and feature).
I really suggest using libusb though.
Related
I am trying to replicate the "-e" option in ncat to redirect stdio in Rust to a remote ncat listener.
I can do it over TcpStream by using dup2 and then executing the "/bin/sh" command in Rust. However, I do not know how to do it over TLS as redirection seems to require file descriptors, which TlsStream does not seem to provide.
Can anyone advise on this?
EDIT 2 Nov 2020
Someone in the Rust forum has kindly shared a solution with me (https://users.rust-lang.org/t/redirect-stdio-pipes-and-file-descriptors/50751/8) and now I am trying to work on how to redirect the stdio over the TLS connection.
let mut command_output = std::process::Command::new("/bin/sh")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("cannot execute command");
let mut command_stdin = command_output.stdin.unwrap();
println!("command_stdin {}", command_stdin.as_raw_fd());
let copy_stdin_thread = std::thread::spawn(move || {
io::copy(&mut io::stdin(), &mut command_stdin)
});
let mut command_stdout = command_output.stdout.unwrap();
println!("command_stdout {}", command_stdout.as_raw_fd());
let copy_stdout_thread = std::thread::spawn(move || {
io::copy(&mut command_stdout, &mut io::stdout())
});
let command_stderr = command_output.stderr.unwrap();
println!("command_stderr {}", command_stderr.as_raw_fd());
let copy_stderr_thread = std::thread::spawn(move || {
io::copy(&mut command_stderr, &mut io::stderr())
});
copy_stdin_thread.join().unwrap()?;
copy_stdout_thread.join().unwrap()?;
copy_stderr_thread.join().unwrap()?;
This question and this answer are not specific to Rust.
You noticed the important fact that the I/O of the redirected process must be file descriptors.
One possible solution in your application is
use socketpair(PF_LOCAL, SOCK_STREAM, 0, fd)
this provides two connected bidirectional file descriptors
use dup2() on one end of this socketpair for the I/O of the redirected process (as you would do with an unencrypted TCP stream)
watch both the other end and the TLS stream (in a select()-like manner for example) in order to
receive what becomes available from the socketpair and send it to the TLS stream,
receive what becomes available from the TLS stream and send it to the socketpair.
Note that select() on a TLS stream (its underlying file descriptor, actually) is a bit tricky because some bytes may already have been received (on its underlying file descriptor) and decrypted in the internal buffer while not yet consumed by the application.
You have to ask the TSL stream if its reception buffer is empty before trying a new select() on it.
Using an asynchronous or threaded solution for this watch/recv/send loop is probably easier than relying on a select()-like solution.
edit, after the edition in the question
Since you have now a solution relying on three distinct pipes you can forget everything about socketpair().
The invocation of std::io::copy() in each thread of your example is a simple loop that receives some bytes from its first parameter and sends them to the second.
Your TlsStream is probably a single structure performing all the encrypted I/O operations (sending as well as receiving) thus you will not be able to provide a &mut reference on it to your multiple threads.
The best is probably to write your own loop trying to detect new incoming bytes and then dispatch them to the appropriate destination.
As explained ebove, I would use select() for that.
Unfortunately in Rust, as far as I know, we have to rely on low-level features as libc for that (there may be other high level solutions I am not aware of in the async world...).
I produced a (not so) minimal example below in order to show the main idea; it is certainly far from being perfect, so « handle with care » ;^)
(it relies on native-tls and libc)
Accessing it from openssl gives this
$ openssl s_client -connect localhost:9876
CONNECTED(00000003)
Can't use SSL_get_servername
...
Extended master secret: yes
---
hello
/bin/sh: line 1: hello: command not found
df
Filesystem 1K-blocks Used Available Use% Mounted on
dev 4028936 0 4028936 0% /dev
run 4038472 1168 4037304 1% /run
/dev/sda5 30832548 22074768 7168532 76% /
tmpfs 4038472 234916 3803556 6% /dev/shm
tmpfs 4096 0 4096 0% /sys/fs/cgroup
tmpfs 4038472 4 4038468 1% /tmp
/dev/sda6 338368556 219588980 101568392 69% /home
tmpfs 807692 56 807636 1% /run/user/9223
exit
read:errno=0
fn main() {
let args: Vec<_> = std::env::args().collect();
let use_simple = args.len() == 2 && args[1] == "s";
let mut file = std::fs::File::open("server.pfx").unwrap();
let mut identity = vec![];
use std::io::Read;
file.read_to_end(&mut identity).unwrap();
let identity =
native_tls::Identity::from_pkcs12(&identity, "dummy").unwrap();
let listener = std::net::TcpListener::bind("0.0.0.0:9876").unwrap();
let acceptor = native_tls::TlsAcceptor::new(identity).unwrap();
let acceptor = std::sync::Arc::new(acceptor);
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let acceptor = acceptor.clone();
std::thread::spawn(move || {
let stream = acceptor.accept(stream).unwrap();
if use_simple {
simple_client(stream);
} else {
redirect_shell(stream);
}
});
}
Err(_) => {
println!("accept failure");
break;
}
}
}
}
fn simple_client(mut stream: native_tls::TlsStream<std::net::TcpStream>) {
let mut buffer = [0_u8; 100];
let mut count = 0;
loop {
use std::io::Read;
if let Ok(sz_r) = stream.read(&mut buffer) {
if sz_r == 0 {
println!("EOF");
break;
}
println!(
"received <{}>",
std::str::from_utf8(&buffer[0..sz_r]).unwrap_or("???")
);
let reply = format!("message {} is {} bytes long\n", count, sz_r);
count += 1;
use std::io::Write;
if stream.write_all(reply.as_bytes()).is_err() {
println!("write failure");
break;
}
} else {
println!("read failure");
break;
}
}
}
fn redirect_shell(mut stream: native_tls::TlsStream<std::net::TcpStream>) {
// start child process
let mut child = std::process::Command::new("/bin/sh")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.expect("cannot execute command");
// access useful I/O and file descriptors
let stdin = child.stdin.as_mut().unwrap();
let stdout = child.stdout.as_mut().unwrap();
let stderr = child.stderr.as_mut().unwrap();
use std::os::unix::io::AsRawFd;
let stream_fd = stream.get_ref().as_raw_fd();
let stdout_fd = stdout.as_raw_fd();
let stderr_fd = stderr.as_raw_fd();
// main send/recv loop
use std::io::{Read, Write};
let mut buffer = [0_u8; 100];
loop {
// no need to wait for new incoming bytes on tcp-stream
// if some are already decoded in the tls-stream
let already_buffered = match stream.buffered_read_size() {
Ok(sz) if sz > 0 => true,
_ => false,
};
// prepare file descriptors to be watched for by select()
let mut fdset =
unsafe { std::mem::MaybeUninit::uninit().assume_init() };
let mut max_fd = -1;
unsafe { libc::FD_ZERO(&mut fdset) };
unsafe { libc::FD_SET(stdout_fd, &mut fdset) };
max_fd = std::cmp::max(max_fd, stdout_fd);
unsafe { libc::FD_SET(stderr_fd, &mut fdset) };
max_fd = std::cmp::max(max_fd, stderr_fd);
if !already_buffered {
// see above
unsafe { libc::FD_SET(stream_fd, &mut fdset) };
max_fd = std::cmp::max(max_fd, stream_fd);
}
// block this thread until something new happens
// on these file-descriptors (don't wait if some bytes
// are already decoded in the tls-stream)
let mut zero_timeout =
unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
unsafe {
libc::select(
max_fd + 1,
&mut fdset,
std::ptr::null_mut(),
std::ptr::null_mut(),
if already_buffered {
&mut zero_timeout
} else {
std::ptr::null_mut()
},
)
};
// this thread is not blocked any more,
// try to handle what happened on the file descriptors
if unsafe { libc::FD_ISSET(stdout_fd, &mut fdset) } {
// something new happened on stdout,
// try to receive some bytes an send them through the tls-stream
if let Ok(sz_r) = stdout.read(&mut buffer) {
if sz_r == 0 {
println!("EOF detected on stdout");
break;
}
if stream.write_all(&buffer[0..sz_r]).is_err() {
println!("write failure on tls-stream");
break;
}
} else {
println!("read failure on process stdout");
break;
}
}
if unsafe { libc::FD_ISSET(stderr_fd, &mut fdset) } {
// something new happened on stderr,
// try to receive some bytes an send them through the tls-stream
if let Ok(sz_r) = stderr.read(&mut buffer) {
if sz_r == 0 {
println!("EOF detected on stderr");
break;
}
if stream.write_all(&buffer[0..sz_r]).is_err() {
println!("write failure on tls-stream");
break;
}
} else {
println!("read failure on process stderr");
break;
}
}
if already_buffered
|| unsafe { libc::FD_ISSET(stream_fd, &mut fdset) }
{
// something new happened on the tls-stream
// (or some bytes were already buffered),
// try to receive some bytes an send them on stdin
if let Ok(sz_r) = stream.read(&mut buffer) {
if sz_r == 0 {
println!("EOF detected on tls-stream");
break;
}
if stdin.write_all(&buffer[0..sz_r]).is_err() {
println!("write failure on stdin");
break;
}
} else {
println!("read failure on tls-stream");
break;
}
}
}
let _ = child.wait();
}
I am working on a BLE Scanner.Basically I am looking for an iBeacon device with 0x4c type and a payload size of 30. However when i run this mbed crashes after spitting out few print lines. This code is very hit and miss.
it is getting an index out of bound error(understandably). How do I catch the error and skip it?
void Scanner::onAdvertisingReport(const AdvertisingReportEvent &event)
{
printf("Looking for Devices\r\n");
AdvertisingDataParser adv_data(event.getPayload());
while(adv_data.hasNext())
{
if (event.getPayload().size() == 30 and event.getPayload()[5] == 0x4c)
{
beacon_found = true;
while(beacon_found)
{
printf("Found Beacon!\r\n");
::print_address(event.getPeerAddress());
printf("RSSI : %d\r\n",event.getRssi());
printf("PL: %d\r\n",event.getPayload().size());
printf("Major Value: %d\r\n",event.getPayload()[26]);
printf("Minor Value: %d\r\n",event.getPayload()[27]);
break;
}
beacon_found = false;
break;
}
else
{
printf("Couldnt find beacon!\r\n");
break;
}
}
adv_data.next();
}
Error:
Error Status: 0x80FF0140 code 324 module 255
Assertion failed: 0 <= index && index < _size in Span.h
I am currently using the azure-iot-sdk-c on the TI CC-3235 microcontroller. I tried using the Azure Direct methods to invoke a method (blinkLED1) on the microcontroller. Azure IoT hub gives me an error saying "not registered" like below:
{"message":"Device {\"Message\":\"{\\\"errorCode\\\":404103,\\\"trackingId\\\":\\\"c1763a63a5b54381aa555198de1e884c-TimeStamp:07/01/2020 12:03:39\\\",\\\"message\\\":\\\"Timed out waiting for device to connect.\\\",\\\"info\\\":{\\\"timeout\\\":\\\"00:03:45\\\"},\\\"timestampUtc\\\":\\\"2020-07-01T12:03:39.1927271Z\\\"}\",\"ExceptionMessage\":\"\"} not registered"}
The code below is a modification of the example code from TI/Microsoft. The microcontroller C code is below:
{
(void)userContextCallback;
(void)payload;
Display_printf(display, 0, 0, "\r\nDevice Method called");
Display_printf(display, 0, 0, "Device Method name: %s", method_name);
Display_printf(display, 0, 0, "Device Method payload: %.*s", (int)size, (const char*)payload);
int status = 200;
char* RESPONSE_STRING = "{ \"Response\": \"This is the response from the device\" }";
Display_printf(display, 0, 0, "\r\nResponse status: %d", status);
Display_printf(display, 0, 0, "Response payload: %s\r\n", RESPONSE_STRING);
if(strcmp("blinkLED1",method_name)==0){
const char deviceMethodResponse[] = "{\"Response\":\"LED Blink1 Received\"}";
Display_printf(display, 0, 0, "\r\nDevice Method called");
*resp_size = sizeof(deviceMethodResponse)-1;
*response = malloc(*resp_size);
(void)memcpy(*response, deviceMethodResponse, *resp_size);
status = 200;
}
*resp_size = strlen(RESPONSE_STRING);
if ((*response = malloc(*resp_size)) == NULL)
{
status = -1;
}
else
{
(void)memcpy(*response, RESPONSE_STRING, *resp_size);
}
g_continueRunning = false;
return status;
}
TI Example reference:iothub_client_sample_device_method
Azure IoT SDK C Reference :Run a simple device Twin C sample on Windows
I've been trying to use the CommonCrypto in iOS to do a blockwise decryption of a larger Data object, but I can't get it to work. I've been reading the documentation, and looked at several examples from Objective-C - none of which I managed to get to work in an Objective-C environment. After 3 days of coding this I'm starting to wear out and I need some help.
I can decrypt and encrypt fine using the CCCrypto approach, but since I use rather large files this eats up too much memory for iOS to allow me to use this method. Thus I need to do this more efficiently and I decided to try an approach where I decipher one block at a time and then replace the block I deciphered with the resulting data block. The code runs, it seems to be working except for the fact that the data I get won't decode back to an UTF8 String.
Code for using CCCryptoCreate() with symmetric block deciphering (DataExtension)
mutating func decryptUsingCCCryptoCreate() {
// Get the first 16 bytes as IV
let IV = self.prefix(kCCBlockSizeAES128)
// Get key as array of bytes
let key = "ABCDEFGHIJKLMNOPQRSABCDEFGHIJKLM".data(using: .utf8) ?? Data()
// Setup totalSize
let totalSize = self.count
let operation = kCCDecrypt
let algorithm = kCCAlgorithmAES
let options = kCCOptionPKCS7Padding
var cryptorRef: CCCryptorRef?
// Step one is to create the CCCryptor with correct parameters for AES128 decryption
var status = CCCryptorCreate(CCOperation(operation), CCAlgorithm(algorithm), CCOptions(options), key.withUnsafeBytes { $0.baseAddress }, key.count, IV.withUnsafeBytes { $0.baseAddress }, &cryptorRef)
if status != kCCSuccess {
print("Failed on create: \(status.description)")
return
}
var dataOutMoved: size_t = 0 // The actual data moved
var dataInLength: size_t = kCCBlockSizeAES128 // The in size will always be the size of a kCCBlockSizeAES128
var dataOutLength: size_t = CCCryptorGetOutputLength(cryptorRef, dataInLength, false) // DataOutLength is always less than or equal to the dataInLength
var totalLength: size_t = 0 // The actual length of the deciphered data
var filePtr: size_t = 0 // Keeps track of the current position in the deciphering process
var startByte: Int = 0 // Increments each time with the kCCBlockSizeAES128 until we are done
var dataIn = Data() // Buffer to store the encrypted block to be deciphered
var dataOut = Data() // Buffer to store the decrypted block result
// While startByte is less than totalSize we continue to decrypt the next block
while startByte <= totalSize {
if startByte + kCCBlockSizeAES128 > totalSize {
dataInLength = totalSize - startByte
} else {
dataInLength = kCCBlockSizeAES128
}
// Next block to decrypt
guard let rangeToDecrypt = Range(NSRange(location: startByte, length: dataInLength)) else { return }
dataIn = self.subdata(in: rangeToDecrypt)
// Decipher the block
status = CCCryptorUpdate(cryptorRef, dataIn.withUnsafeBytes { $0.baseAddress }, dataInLength, dataOut.withUnsafeMutableBytes { $0.baseAddress }, dataOutLength, &dataOutMoved)
if status != kCCSuccess {
print("Failed on Update: \(status.description)")
return
}
// Replace the encrypted block with the decrypted block
let rangeToReplace = Range(NSRange(location: filePtr, length: dataOutMoved))!
self.replaceSubrange(rangeToReplace, with: dataOut.withUnsafeBytes { $0.baseAddress! }, count: dataOutMoved)
totalLength += dataOutMoved
filePtr += dataOutMoved
startByte += kCCBlockSizeAES128
}
// Finalize the deciphering
status = CCCryptorFinal(cryptorRef, dataOut.withUnsafeMutableBytes { $0.baseAddress }, dataOutLength, &dataOutMoved)
totalLength += dataOutMoved
if status != kCCSuccess {
print("Failed on final: \(status.description)")
return
}
// We replace the final deciphered block
let decryptedRange = Range(NSRange(location: filePtr, length: dataOutMoved))!
self.replaceSubrange(decryptedRange, with: dataOut.withUnsafeBytes { $0.baseAddress! }, count: dataOut.count)
// Since we are using padding the CCCryptorFinal can contain padding which needs to be truncated.
self = self.prefix(totalLength)
// Finish the CCCryptor process
CCCryptorRelease(cryptorRef)
}
Code for the encryption using CCCrypto()
mutating func encryptUsingCCCrypto() {
let sa = String(data: self, encoding: .utf8) ?? ""
print("Before encryption: \(sa)")
let now = Date()
let key = "ABCDEFGHIJKLMNOPQRSABCDEFGHIJKLM".data(using: .utf8) ?? Data()
let ivRandomData = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
let blockSize = kCCBlockSizeAES128
let bufferSize = self.count + blockSize
var encryptedSize = 0
let cryptStatus = CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES),
UInt32(kCCOptionPKCS7Padding),
key.withUnsafeBytes { $0.baseAddress },
key.count,
ivRandomData.withUnsafeBytes { $0.baseAddress },
self.withUnsafeBytes { $0.baseAddress },
self.count,
self.withUnsafeMutableBytes { $0.baseAddress },
bufferSize,
&encryptedSize)
self = self.prefix(encryptedSize)
let s = String(data: self, encoding: .utf8) ?? ""
print("Result: \(s)")
}
I use the code like this:
let string = "1234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234"
var data = string.data(using: .utf8) ?? Data()
data.encryptUsingCCCrypto()
data.decryptUsingCCCryptoCreate() // I get a Data object with 112 bytes here
let s = String(data: data, encoding: .utf8) ?? "" // String is nil, and is provided ""
There is a client which is implemented in Nodejs. I wand to send post request to Apache HTTP server and then that request is to be forwarded to back end server(It locates at somewhere else).
So I implemented Node js client and Apache module. Request and response between those two are ok. Now my problem is how to forward this request from Apache HTTP server to back end server.
Nodejs client.js
var request = require('request');
var userDetails={
username:"username",
password:"abc123"
}
var optsSingup = {
url: "http://localhost:80/a",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
form:{
username:userDetails.username,
password:userDetails.password,
}
};
request(optsSingup, function (err, res, body) {
console.log('error', err);
//console.log('status', res.statusCode);
console.log('body', body);
});
Apache module (I've been following this tutorial http://httpd.apache.org/docs/2.4/developer/modguide.html example mod_example_config.c). Here I will share handler part of my module. Others parts are same as mod_example_config.c.
typedef struct {
const char* key;
const char* value;
} keyValuePair;
static int example_handler(request_rec *r)
{
formData = readPost(r);
if (formData) {
int i;
for (i = 0; &formData[i]; i++) {
if (formData[i].key && formData[i].value) {
ap_rprintf(r, "%s = %s\n", formData[i].key, formData[i].value);
} else if (formData[i].key) {
ap_rprintf(r, "%s\n", formData[i].key);
} else if (formData[i].value) {
ap_rprintf(r, "= %s\n", formData[i].value);
} else {
break;
}
}
}
return OK;
}
keyValuePair* readPost(request_rec* r) {
apr_array_header_t *pairs = NULL;
apr_off_t len;
apr_size_t size;
int res;
int i = 0;
char *buffer;
keyValuePair* kvp;
res = ap_parse_form_data(r, NULL, &pairs, -1, HUGE_STRING_LEN);
if (res != OK || !pairs) return NULL;
kvp = apr_pcalloc(r->pool, sizeof(keyValuePair) * (pairs->nelts + 1));
while (pairs && !apr_is_empty_array(pairs)) {
ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs);
apr_brigade_length(pair->value, 1, &len);
size = (apr_size_t) len;
buffer = apr_palloc(r->pool, size + 1);
apr_brigade_flatten(pair->value, buffer, &size);
buffer[len] = 0;
kvp[i].key = apr_pstrdup(r->pool, pair->name);
kvp[i].value = buffer;
i++;
}
return kvp;
}
Actually this is not the proper way to do this. Please see the answer in this question How to set a Set Handler for proxy request