I've got a very simple encryption/decryption program that works fine without FIPS support enabled, but fails when it is:
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
/* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
int main (void)
{
/* Force FIPS initialization */
FIPS_mode_set(1);
/* Set up the key and iv. Do I need to say to not hard code these in a
* real application? :-)
*/
/* A 256 bit key */
unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"01234567890123456";
/* Message to be encrypted */
unsigned char *plaintext =
(unsigned char *)"The quick brown fox jumps over the lazy dog";
/* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, dependant on the
* algorithm and mode
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
int decryptedtext_len, ciphertext_len;
/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
/* Encrypt the plaintext */
ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
ciphertext);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);
/* Clean up */
EVP_cleanup();
ERR_free_strings();
return 0;
}
As you can see, just the demo code with FIPS enabled. Without FIPS, my output is:
Ciphertext is:
0000 - e0 6f 63 a7 11 e8 b7 aa-9f 94 40 10 7d 46 80 a1 .oc.......#.}F..
0010 - 17 99 43 80 ea 31 d2 a2-99 b9 53 02 d4 39 b9 70 ..C..1....S..9.p
0020 - 2c 8e 65 a9 92 36 ec 92-07 04 91 5c f1 a9 8a 44 ,.e..6.....\...D
Decrypted text is:
The quick brown fox jumps over the lazy dog
With FIPS, compilation goes fine, but generates the following when run:
139686960322208:error:2D0A0086:FIPS routines:FIPS_cipher:selftest failed:fips_enc.c:336:
139686960322208:error:2D0A0086:FIPS routines:FIPS_cipher:selftest failed:fips_enc.c:336:
I've tried both as a C project, and as a C++ project, pointing the CC env variable at both the fipsld script, and the modified fipsld++ script as appropriate. My FIPSLD_CC variable points to gcc as noted in the FIPS documentation.
What am I missing here?
Related
I am testing a serial communication protocol based on printable characters only.
The setup has a pc connected to an arduino board by USB. The PC USB serial is operated in canonical mode, with no echo, no flow control, 9600 baud.
Since a read timeout is requested, pselect is called before the serial read. The arduino board simply echoes back every received character without any processing. The PC OS is Linux Neon with kernel 5.13.0-40-generic.
When lines of a specific length are transmitted from the PC and echoed back by the arduino, they are received correctly except for the final new line that is missing.
A further read, returns an empty line (the previously missing NL).
Lines with different length are transmitted and received correctly, including the trailing NL.
This behavior is fully repeatable and stable. The following code reproduce the problem for a line transmitted with a length of 65 characters (including NL) and received with a length of 64 (NL missing). Other line lengths work fine.
Thanks for any hints.
/* remote serial loop test 20220626 */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#define TX_MINLEN 63
#define TX_MAXLEN 66
#define DATA_MAXLEN 128
#define LINK_DEVICE "/dev/ttyUSB0"
#define LINK_SPEED B9600
#define RECEIVE_TIMEOUT 2000
int main()
{
int wlen;
int retval;
int msglen;
uint8_t tx_data[257] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
for (int i=16; i < 256; i++) tx_data[i] = tx_data[i & 0xf];
uint8_t rx_data[257];
/* serial interface */
char * device;
int speed;
int fd;
fd_set fdset;
struct timespec receive_timeout;
struct timespec *p_receive_timeout = &receive_timeout;
struct termios tty;
/* open serial device in blocking mode */
fd = open(LINK_DEVICE, O_RDWR | O_NOCTTY);
if (fd < 0) {
printf("Error opening %s: %s\n",LINK_DEVICE,strerror(errno));
return -1;
}
/* prepare serial read by select to have read timeout */
FD_ZERO(&(fdset));
FD_SET(fd,&(fdset));
if (RECEIVE_TIMEOUT >= 0) {
p_receive_timeout->tv_sec = RECEIVE_TIMEOUT / 1000;
p_receive_timeout->tv_nsec = RECEIVE_TIMEOUT % 1000 * 1000000;
}
else
p_receive_timeout = NULL;
/* get termios structure */
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
/* set tx and rx baudrate */
cfsetospeed(&tty, (speed_t)LINK_SPEED);
cfsetispeed(&tty, (speed_t)LINK_SPEED);
/* set no modem ctrl, 8 bit, no parity, 1 stop */
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* canonical mode: one line at a time (\n is line terminator) */
tty.c_lflag |= ICANON | ISIG;
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
/* input control */
tty.c_iflag &= ~IGNCR; /* preserve carriage return */
tty.c_iflag &= ~INPCK; /* no parity checking */
tty.c_iflag &= ~INLCR; /* no NL to CR traslation */
tty.c_iflag &= ~ICRNL; /* no CR to NL traslation */
tty.c_iflag &= ~IUCLC; /* no upper to lower case mapping */
tty.c_iflag &= ~IMAXBEL;/* no ring bell at rx buffer full */
tty.c_iflag &= ~(IXON | IXOFF | IXANY);/* no SW flowcontrol */
/* no output remapping, no char dependent delays */
tty.c_oflag = 0;
/* no additional EOL chars, confirm EOF to be 0x04 */
tty.c_cc[VEOL] = 0x00;
tty.c_cc[VEOL2] = 0x00;
tty.c_cc[VEOF] = 0x04;
/* set changed attributes really */
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
/* wait for serial link hardware to settle, required by arduino reset
* triggered by serial control lines */
sleep(2);
/* empty serial buffers, both tx and rx */
tcflush(fd,TCIOFLUSH);
/* repeat transmit and receive, each time reducing data length by 1 char */
for (int l=TX_MAXLEN; l > TX_MINLEN - 1; l--) {
/* prepare data: set EOL and null terminator for current length */
tx_data[l] = '\n';
tx_data[l+1] = 0;
/* send data */
int sent = write(fd,tx_data,l+1);
/* receive data */
/* wait for received data or for timeout */
retval = pselect(fd+1,&(fdset),NULL,NULL,p_receive_timeout,NULL);
/* check for error or timeout */
if (retval < 0)
printf("pselect error: %d - %s\n",retval,strerror(errno));
else if (retval == 0)
printf("serial read timeout\n");
/* there is enough data for a non block read: do read */
msglen = read(fd,&rx_data,DATA_MAXLEN);
/* check rx data length */
if (msglen != l+1)
printf("******** RX ERROR: sent %d, received %d\n",l+1,msglen);
else
continue;
/* check received data, including new line if present */
for (int i=0; i < msglen; i++) {
if (tx_data[i] == rx_data[i])
continue;
else {
printf("different rx data:|%s|\n",rx_data);
break;
}
}
/* clear RX buffer */
for (int i=0; i < msglen + 1; i++) rx_data[i] = 0;
}
}
When performing stream-based communication, be it via pipes, serial ports, or TCP sockets, you can never rely on reads to always return a full "unit of transmission" (in this case a line, but could also be a fixed-size block). The reason is that stream-based communication can always be split by any part of the transmission stack (even potentially the sender) into multiple blocks, and there is never a guarantee that a single read will always read a full block.
For example, you could always run into the race condition that your microcontroller is still sending parts of the message when you call read(), so not all characters are read exactly. In your case, that's not what you're seeing, because that would be more of a stochastic phenomenon (that would be worse with an increased interrupt load on the computer) and not so easily reproducible. Instead, because you're talking about the number 64 here, you're running into the static buffer size used in the kernel's tty driver that will only ever return at most 64 bytes at once, regardless of what the specified read size actually is. However, in other cases it could still be that you'll see additional failures by the kernel returning only the first couple of characters of a line in the first read(), and the rest in the second, depending on precise timing details -- you've probably not seen that yet, but it's bound to happen at some point.
The only reliable way to properly implement communication protocols in streaming situations (serial port, pipes, TCP sockets, etc.) is to consider the following:
For fixed-size data (e.g. communication units that are always N bytes in size) to loop around a read() call until you've read exactly the right amount of bytes (reads that follow an incomplete read would obviously ask for less bytes than the original read, just to make up the difference)
For variable-size data (for example communication units that are separated by a line end character) you have two options: either you read only one character at a time until you reach the end-of-line character (inefficient, uses lots of syscalls), or you keep track of the communication state via a large enough buffer that you constantly fill with read() operations until the buffer contains a line-end character, at which point you remove that line from the buffer (but keep the rest) and process that.
As a complete aside, if you're doing anything with serial communication, I can very much recommend the excellent libserialport library (LGPLv3 license) that makes working with serial ports a lot easier -- and has the benefit of being cross-platform. (Doesn't help with your issue, just thought that I'd mention it.)
Upgrading from linux kernel version 5.13.0-40-generic to 5.13.0-51-generic solved the problem.
I have created my functions to send and receive from the UART, and sending the data does not seem to be a problem. In the data visualizer we can see the values and even plot them.
However when sending these data through the bluetooth, we cannot get the values to plot them in any of many available apps.
I believe there is a problem with the way we are sending data through the UART and to the bluetooth and that is why we cannot then get the values to be plotted.
Being a starter at all this, I would like to someone please advice us if the code below is ok, if there is a mistake and if there is a better way to send the data through the UART so as to make the Bluetooth work properly. Target is to be able to plot (graph) the values on the phone.
Many thanks
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
//----------VARIABLES
float V_n,V_nm1,V_measure=0;
volatile int Velo_pulse;
float Exp_fltr_Coeff=0.2;
unsigned int Counter_ADC=0b0001;
unsigned int Value1;
char String[]="";
//----------Functions Definition
//---timers
void Timer1_Control();
void AttachInterrupt();
//---AnalogueRead
void Set_Ports();
void AnalogRead_Setup();
unsigned int AnalogRead();
//---UART
void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr, unsigned int Value1);
int main(void){
USART_init(); //Call the USART initialization code
Set_Ports();
AnalogRead_Setup();
AttachInterrupt();
Timer1_Control();
sei();
while(1){
_delay_ms(1);
}
return 0;
}
void USART_init(void){
UBRR0H = (unsigned char)(BAUD_PRESCALLER>>8); //UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (unsigned char)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0); //Enable receiver / transmitter
UCSR0C = (1<<USBS0)|(3<<UCSZ00); //Set frame format: 8data, 2stop bit
}
unsigned char USART_receive(void){
while(!(UCSR0A & (1<<RXC0))); //Wait for data to be received (buffer RXCn in the UCSRnA register)
return UDR0;
}
void USART_send( unsigned char data){
while(!(UCSR0A & (1<<UDRE0))); //Waiting for empty transmit buffer (buffer UDREn in the UCSRnA register)
UDR0 = data; //Loading Data on the transmit buffer
}
void USART_putstring(char* String, unsigned int Value1){
sprintf(String,"%d\r\n",Value1);
while(*String != 0x00){
USART_send(*String);
String++;}
}
void Set_Ports()
{
DDRD = 0b11111111; //All port is output
DDRD ^= (1 << DDD5); // PD5 is now input
}
ISR(ADC_vect)
{
//ADMUX ^= Counter_ADC; //Swapping between ADC0 an ADC1
}
void AnalogRead_Setup()
{
ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (0 << ADPS0); // Set ADC prescaler to 16 - 1 MHz sample rate # 16MHz
ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
ADCSRA |= (1 << ADATE); // Set ADC to Free-Running Mode
ADCSRA |= (1 << ADIE); // Interrupt in Conversion Complete
ADCSRA |= (1 << ADEN); // Enable ADC
}
unsigned int AnalogRead(unsigned int PortVal)
{
if (PortVal==5){
ADMUX |= (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (1 << MUX0); //sets the pin 0101 sets pin5
} else if (PortVal==4){
ADMUX |= (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (0 << MUX0); //sets the pin 0101 sets pin4
}
ADCSRA |= (1 << ADSC); // Start A2D Conversions
//while(ADCSRA & (1 << ADSC));
return ADCH;
}
//----------Timer Functions
ISR (TIMER1_COMPA_vect) // Timer1 ISR (compare A vector - Compare Interrupt Mode)
{
cli();
V_measure=(Velo_pulse*60/0.250);
//USART_putstring(String,Velo_pulse);
Velo_pulse=0;
V_n=Exp_fltr_Coeff*V_measure+(1-Exp_fltr_Coeff)*V_nm1;
V_nm1=V_n;
USART_putstring(String,(int)V_n);
sei();
}
ISR (INT0_vect)
{
Velo_pulse++;
//USART_putstring(String,Velo_pulse);
}
void Timer1_Control()
{
TCCR1A=0b00000000; //Clear the timer1 registers
TCCR1B=0b00000000;
TCNT1=0b00000000;
TCCR1B=0b00001101; //Sets prescaler (1024) & Compare mode
OCR1A=2604; // 160ms - 6 Hz
TIMSK1=0b00000010;
}
void AttachInterrupt()
{
DDRD ^= (1 << DDD2); // PD2 (PCINT0 pin) is now an input
PORTD |= (1 << PORTD2); // turn On the Pull-up // PD2 is now an input with pull-up enabled
EICRA = 0b00000011; // set INT0 to trigger on rising edge change
EIMSK = 0b00000001; // Turns on INT0
}
Look at string initialization:
char String[]="";
this allocates an array of chars with a size of 1 item (which is terminating zero).
Then you make a call, passing this array reference as the first parameter:
USART_putstring(String,(int)V_n);
And the USART_putstring is as follows:
void USART_putstring(char* String, unsigned int Value1){
sprintf(String,"%d\r\n",Value1);
while(*String != 0x00){
USART_send(*String);
String++;}
}
Note sprintf(String,"%d\r\n",Value1); it converts numeric value into the char buffer. I.e. the buffer should be large enough to contain the text representation of the number, line feeds \r\n\ and zero - the string terminator.
But since your string buffer has size for only 1 char, it totally depends on luck, what will happen after sprintf: maybe there is some unused memory area, so the whole thing will look as if it working. Maybe there are some other variables, and their value will be overwritten, which makes the program behavior unexpected in the future. Or maybe there is some essential data, and your app will be crashing. Behavior may change after you adding several lines and recompile the code.
The point is: be careful with your buffers. Instead of using constants for initialization, set the exact size for the buffer. The number length is maximum 6 symbols (1 possible sign and 5 digits, assuming you're using AVR-GCC, which has the int 16-bits wide, thus has -32768 as the minimum) + 2 for \r\n\ + 1 for terminating zero. I.e. size of the buffer should be 9 at least.
char String[9];
In the core bluetooth 4.2 documentation here it talks about a CRC check for data integrity (P2456). This details the below:
With an example below:
4e 01 02 03 04 05 06 07 08 09
Producing CRC: 6d d2
I have tried a number of different methods but can't seem to reproduce the example. Can anyone provide some sample code to produce the CRC above.
You left out a key part of the example in the document, which is that the UAP used in the example is 0x47. The CRC needs to be initialized with the UAP. (Oddly, with the bits reversed and in the high byte, relative to the data bits coming in.)
The code below computes the example. The result is d26d. The CRC is transmitted least significant bit first, so it is sent 6d d2. On the receive side the same CRC is computed on the whole thing with the CRC, and the result is zero, which is how the receive side is supposed to check what was sent.
#include <stdio.h>
static unsigned crc_blue(unsigned char *payload, size_t len) {
unsigned crc = 0xe200; // UAP == 0x47
while (len--) {
crc ^= *payload++;
for (int k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;
}
return crc;
}
int main(void) {
unsigned char payload[] = {
0x4e, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
printf("%04x\n", crc_blue(payload, sizeof(payload)));
unsigned char recvd[] = {
0x4e, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x6d, 0xd2};
printf("%04x\n", crc_blue(recvd, sizeof(recvd)));
return 0;
}
Your code would need to initialize the UAP appropriately for that device.
I'm writing a program in linux which counts the serial number (xxxx-xxxx) of the volume of the CD in Windows 7. My program correctly determines the serial number of the volume on disks with the filesystems iso9660 and joilet. But how to define a disk volume sniffer with a file system udf? Can someone tell me ....
ps if anyone does not understand I'm talking about the serial number of this kind https://extra-torrent.jimdo.com/2016/01/23/hard-disk-volume-serial-number-change/
#include <QCoreApplication>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
#include <string.h>
#include <szi/szimac.h>
#include <qfile.h>
#include <iostream>
#include <QDir>
#include <unistd.h>
#define SEC_SIZE 2048
#define VD_N 16
#define VD_TYPE_SUPP 2
#define VD_TYPE_END 255
#define ESC_IDX 88
#define ESC_LEN 3
#define ESC_UCS2L1 "%/#"
#define ESC_UCS2L2 "%/C"
#define ESC_UCS2L3 "%/E"
using namespace std;
int cdid(unsigned char pvd[SEC_SIZE])
{
unsigned char part[4] = {0};
int i;
for(i = 0; i < SEC_SIZE; i += 4)
{
part[3] += pvd[i + 0];
part[2] += pvd[i + 1];
part[1] += pvd[i + 2];
part[0] += pvd[i + 3];
}
return (part[3] << 24) + (part[2] << 16) + (part[1] << 8) + part[0];
}
int main(int argc, char *argv[])
{
FILE *in;
unsigned char buf[SEC_SIZE];
struct cdrom_multisession msinfo;
long session_start;
int id;
QString home=QString(getenv("HOME"))+QString("/chteniestorm");
QFile file(home);
ustr="/dev/sr0";
in = fopen(ustr.toLocal8Bit().data(), "rb");
if(in == NULL)
{
if (file.open(QIODevice::WriteOnly))
{
file.write("sernom=1");
file.close();
}
cout<<"netdiska"<<endl;
return 0;
}
/* Get session info */
msinfo.addr_format = CDROM_LBA;
if(ioctl(fileno(in), CDROMMULTISESSION, &msinfo) != 0)
{
fprintf(stderr, "WARNING: Can't get multisession info\n");
perror(NULL);
session_start = 0;
}
else
{
session_start = msinfo.addr.lba;
}
fseek(in, 0, SEEK_SET); //to the begining
/* Seek to primary volume descriptor */
if(fseek(in, (session_start + VD_N) * SEC_SIZE, SEEK_SET) != 0)
{
if (file.open(QIODevice::WriteOnly))
{
file.write("sernom=2");
file.close();
}
fclose(in);
return 0;
}
/* Read descriptor */
if(fread(buf, 1, SEC_SIZE, in) != SEC_SIZE)
{
if (file.open(QIODevice::WriteOnly))
{
file.write("sernom=3");
file.close();
}
fclose(in);
return 0;
}
/* Caclculate disc id */
id = cdid(buf);
/* Search for Joliet extension */
while(buf[0] != VD_TYPE_END)
{
/* Read descriptor */
if(fread(buf, 1, SEC_SIZE, in) != SEC_SIZE)
{
perror(NULL);
return 0;
}
if(buf[0] == VD_TYPE_SUPP
&& (memcmp(buf + ESC_IDX, ESC_UCS2L1, ESC_LEN) == 0
|| memcmp(buf + ESC_IDX, ESC_UCS2L2, ESC_LEN) == 0
|| memcmp(buf + ESC_IDX, ESC_UCS2L3, ESC_LEN) == 0)
)
{
/* Joliet found */
id = cdid(buf);
}
}
fclose(in);
}
It looks like this question was asked on more places [1], [2], [3], [4] but nowhere was answered yet. So I will do it here.
In some of those posts people decoded serial number generation algorithm. It is just checksum which you already have found and put into your cdid() function. Same checksum algorithm is used for both ISO9660 and UDF filesystems on Windows. You have already figured out from which ISO9660 structures is that checksum calculated.
So your question remain just for UDF filesystem. For UDF filesystem on Windows that checksum is calculated from the 512 bytes long File Set Descriptor (FSD) structure. I would suggest you to read OSTA UDF specification how to locale that FSD on UDF disc.
Basically for plain UDF which do not use Virtual Allocation Table (VAT), Sparing Table or Metadata Partition, location of the FSD is stored in Logical Volume Descriptor (LVD) structure, in field LogicalVolumeContentsUse (it is of type long_ad). LVD is stored in the Volume Descriptor Sequence (VDS). VDS's location is stored in Anchor Volume Descriptor Pointer (AVDP), in field MainVolumeDescriptorSequenceExtent. AVDP itself is located at sector 256 of medium. Optical media have sector size 2048 bytes and common hard disk 512 bytes.
For UDF with VAT (e.g. on CD-R/DVD-R/BD-R), Sparing Table (e.g. on CD-RW/DVD-RW) or Metadata Partition (e.g. on Blu-ray), it is much more complicated. You need to look into Virtual, Sparable or Metadata Partition to figure out how to translate logical location of the FSD to physical location of media.
In udftools project starting with version 2.0, there is a new tool udfinfo which provides various information about UDF filesystem. It shows also that Windows specific Volume Serial Number from your question under winserialnum key. Note that udfinfo cannot read FSD from UDF filesystem with VAT or Metadata yet.
I'm trying to programmatically modify some of the properties of my xkb keyboard mapping in X11. In the XkbClientMapRec struct map member of the XkbDescRec struct, we have the following members:
typedef struct { /* Client Map */
unsigned char size_types; /* # occupied entries in types */
unsigned char num_types; /* # entries in types */
XkbKeyTypePtr types; /* vector of key types used by this keymap */
unsigned short size_syms; /* length of the syms array */
unsigned short num_syms; /* # entries in syms */
KeySym * syms; /* linear 2d tables of keysyms, 1 per key */
XkbSymMapPtr key_sym_map; /* 1 per keycode, maps keycode to syms */
unsigned char * modmap; /* 1 per keycode, real mods bound to key */
} XkbClientMapRec, *XkbClientMapPtr;
Then, we have the XkbSymMapRec struct, here:
#define XkbNumKbdGroups 4
#define XkbMaxKbdGroup (XkbNumKbdGroups-1)
typedef struct { /* map to keysyms for a single keycode */
unsigned char kt_index[XkbNumKbdGroups]; /* key type index for each group */
unsigned char group_info; /* # of groups and out of range group handling */
unsigned char width; /* max # of shift levels for key */
unsigned short offset; /* index to keysym table in syms array */
} XkbSymMapRec, *XkbSymMapPtr;
The KeySym * syms array in the XkbClientMapRec array is of course just an array of KeySyms (actually, an array of 2D arrays) as defined in keysymdefs.h.
Anyways, what I'm wondering here is how to add completely new KeySyms to that syms array. Basically I want to completely change the mapping for one of the key codes on my keyboard, and the KeySym that I want to equate is with isn't typically in the KeySyms array. Reassigning a keycode to an existing and defined set of KeySyms is easy - for example, if I wanted keycode 45 to do the same thing as keycode 63, I'd do this:
XkbDescPtr desc = XkbGetKeyboard( curr_display, XkbAllComponentsMask, XkbUseCoreKbd );
XkbSymMapRec * client_map = desc->map;
client_map->key_sym_map[ 45 ] = client_map->key_sym_map[ 23 ];
XkbMapChangesRec changes;
changes.changed = XkbKeySymsMask;
changes.first_key_sym = 45;
changes.num_key_syms = 1;
XkbChangeMap( curr_display, desc, &changes );
This works, but it isn't what I want. I want to create completely new KeySym entries in client_map->sym and assign client_map->key_sym_map[ 45 ]->kt_index[ 0..n ] to those new entries. Unfortunately, this doesn't seem to be possible? The XbkMapChangesRec struct doesn't have any way of stipulating that the KeySym * syms array has been reallocated to something larger. The best that it has is XkbKeySymsMask which is ONLY for changes to key_sym_map.
Any ideas?