Fastest reimplementation PHP's htmlspecialchars function in C - php

I need the default behaviour (i.e ENT_COMPAT | ENT_HTML401) of the PHP-function htmlspecialchars() in C, how is this done best (that means fastest) in C?
I don't need the input string, therefore an in-place solution is possible.
It is a really simple function, it just converts these characters:
'&' -> '&'
'"' -> '"'
'<' -> '<'
'>' -> '>'
What strategy would be fastest? Looping over each character individually and creating the output buffer byte-for-byte, overwriting the input string in-place or some other solution?

This code assumes that input and output are buffers and that input contains the input string. It also assumes that the output buffer is large enough to hold the output (if not output is truncated):
long i = 0;
long j = 0;
while (input[i])
{
if (input[i] == '<')
{
memcpy(&output[j], "<", 4);
j += 4;
} else if (input[i] == '>')
{
memcpy(&output[j], ">", 4);
j += 4;
} else if (input[i] == '"')
{
memcpy(&output[j], """, 6);
j += 6;
} else if (input[i] == '&')
{
memcpy(&output[j], "&", 5);
j += 5;
} else
{
output[j++] = input[i];
}
if (j > sizeof(output)-7)
{
break;
}
i++;
}
output[j] = 0;
In C, ugly code is often the fastest.
An in-place solution would only yield performance benefits if the characters to be exchanged would be very, very rare so that the whole string can be reordered (very expensive) on every character that is detected. With normal HTML-data, where these 4 characters will appear often, an in-place solution would be much slower.

You can build a solution that works in both cases:
Calculates the required space and return an allocated string when NULL is passed, otherwise fill the passed string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static size_t encode_len(const char *str)
{
size_t len = 0;
while (*str) {
if (*str == '"' || *str == '&' || *str == '<' || *str == '>') {
len += 5;
} else {
len += 1;
}
str++;
}
return len;
}
static char *encode(const char *str, char *dest)
{
char *ptr;
if (dest == NULL) {
dest = malloc(encode_len(str) + 1);
if (dest == NULL) return NULL;
}
ptr = dest;
while (*str) {
switch (*str) {
case '"': memcpy(ptr, """, 5); ptr += 5; break;
case '&': memcpy(ptr, "&", 5); ptr += 5; break;
case '<': memcpy(ptr, "<", 5); ptr += 5; break;
case '>': memcpy(ptr, ">", 5); ptr += 5; break;
default: *ptr++ = *str;
}
str++;
}
*ptr = *str;
return dest;
}
int main(void)
{
/* Returns an allocated string */
char *str = encode("testing & <> \"", NULL);
if (str) {
printf("%s\n", str);
free(str);
}
/* Fills a passed string */
char str2[128];
encode("testing & <> \"", str2);
printf("%s\n", str2);
return 0;
}

Here is htmlspecialchars function safe implementation.
Info
char *_output is the result.
size_t outlen is the maximum number of bytes allowed to write to _output.
char *_input is the string to be HTML escaped.
size_t inlen is the length of string to be escaped (excluding null terminator).
This function returns the number of bytes written to _output, including null terminator.
Note: This function always puts null terminator to the _output.
Code
#include <stdio.h>
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#define likely(EXPR) __builtin_expect(!!(EXPR), 1)
#define unlikely(EXPR) __builtin_expect(!!(EXPR), 0)
/*
* `char *_output` is the result.
*
* `size_t outlen` is the maximum number of bytes allowed to write to `_output`.
*
* `char *_input` is the string to be HTML escaped.
*
* `size_t inlen` is the length of string to be escaped (excluding null
* terminator).
*
* This function returns the number of bytes written to `_output`, including
* null terminator.
*
* Note: This function always puts null terminator to the `_output`.
*
*/
size_t htmlspecialchars(char * restrict _output, size_t outlen,
const char * restrict _input, size_t inlen)
{
struct html_char_map {
const char to[8];
const uint8_t len;
};
static const struct html_char_map html_map[0xffu] = {
['<'] = {"<", 4},
['>'] = {">", 4},
['"'] = {""", 6},
['&'] = {"&", 5},
};
size_t j = 0;
uint8_t len = 0;
unsigned char * restrict output = (unsigned char *)_output;
const unsigned char * restrict input = (const unsigned char *)_input;
const unsigned char *in_end = input + inlen;
while (likely(input < in_end)) {
const unsigned char *cp;
const struct html_char_map *map_to = &html_map[(size_t)*input];
if (*map_to->to == '\0') {
cp = input;
len = 1;
} else {
cp = (const unsigned char *)map_to->to;
len = map_to->len;
}
if (unlikely((j + len - 1) >= outlen))
break;
memcpy(&output[j], cp, len);
j += len;
input++;
}
if (likely(outlen > 0)) {
if (unlikely((j + 1) > outlen))
j -= len;
output[++j] = '\0';
}
return j;
}
int main(void)
{
size_t len;
char output[0xff];
const char input[] = "Google<<>>";
const char expected_output[] = "<a href="https://www.google.com">Google</a><<>>";
/* Input length (without null terminator) */
size_t input_len = sizeof(input) - 1;
/* Max allowed write bytes */
size_t output_size = sizeof(output);
len = htmlspecialchars(output, output_size, input, input_len);
/* `len` includes null terminator char */
printf("Written bytes to output: %zu\n", len);
/* `output` */
printf("output = %s\n", output);
assert(!memcmp(output, expected_output, sizeof(expected_output)));
}

Related

How to see the source code / content of a built in function in PHP?

Is there an easy way in PHP to figure out the source code/content of a built in function?
Say for example I want to know what base64_decode() actually does to the given encoded base64 string to convert it to a plain text. How can I achieve this?
You can browse the source code of PHP here
In your case base64_decode is implemented here (PHP 5.6.0)
Note: This code is in C since that's what PHP is written in. In fact all built-in functions and extensions of PHP are written in C.
PHPAPI unsigned char *php_base64_decode_ex(const unsigned char *str, int length, int *ret_length, zend_bool strict) /* {{{ */
{
const unsigned char *current = str;
int ch, i = 0, j = 0, k;
/* this sucks for threaded environments */
unsigned char *result;
result = (unsigned char *)safe_emalloc(length, 1, 1);
/* run through the whole string, converting as we go */
while ((ch = *current++) != '\0' && length-- > 0) {
if (ch == base64_pad) {
if (*current != '=' && ((i % 4) == 1 || (strict && length > 0))) {
if ((i % 4) != 1) {
while (isspace(*(++current))) {
continue;
}
if (*current == '\0') {
continue;
}
}
efree(result);
return NULL;
}
continue;
}
ch = base64_reverse_table[ch];
if ((!strict && ch < 0) || ch == -1) { /* a space or some other separator character, we simply skip over */
continue;
} else if (ch == -2) {
efree(result);
return NULL;
}
switch(i % 4) {
case 0:
result[j] = ch << 2;
break;
case 1:
result[j++] |= ch >> 4;
result[j] = (ch & 0x0f) << 4;
break;
case 2:
result[j++] |= ch >>2;
result[j] = (ch & 0x03) << 6;
break;
case 3:
result[j++] |= ch;
break;
}
i++;
}
k = j;
/* mop things up if we ended on a boundary */
if (ch == base64_pad) {
switch(i % 4) {
case 1:
efree(result);
return NULL;
case 2:
k++;
case 3:
result[k] = 0;
}
}
if(ret_length) {
*ret_length = j;
}
result[j] = '\0';
return result;
}

Secure communication between arduino and PHP using RC4 and base64

I'm trying to make a mildly secure communication between Arduino and PHP. I can not use SSL for lack of power on the Arduino. So I wanted to use RC4 to encrypt data from PHP, and receive into the Arduino and decrypt. also encrypt from the Arduino and send to PHP.
The problem is that the encrypted data sent from PHP, do not coincide in the Arduino.
On PHP I get HesshwkfFk8Q in base64 and in the Arduino i get nZcwrlpZEr0V in base64.
different results when they should be equal.
I think I have a wrong Arduino RC4 implementation. I'm using this https://github.com/adamvr/arduino-base64
This is the code:
Arduino
#include <Base64.h>
unsigned char S[256];
char has[512];
#define S_SWAP(a,b) do { int t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
void rc4(char *key, char *data){
int i,j;
for (i=0;i<256;i++){
S[i] = i;
}
j = 0;
for (i=0;i<256;i++){
j = (j+S[i]+key[i%strlen(key)]) %256;
S_SWAP(S[i],S[j]);
}
i = j = 0;
for (int k=0;k<strlen(data);k++){
i = (i+1) %256;
j = (j+S[i]) %256;
S_SWAP(S[i],S[j]);
has[k] = data[k]^S[(S[i]+S[j]) %256];
}
has[strlen(data)+1] = '\0';
}
void setup() {
Serial.begin(9600);
char key[] = "Hello";
char sdata[] = "secretMsg";
rc4(key,sdata);
Serial.print("Encrypted : ");
char out[100];
base64_encode(out,has,strlen(has));
Serial.println(out);
char out2[100];
base64_decode(out2,out,strlen(out));
rc4(key,out2);
Serial.print("Decrypted : ");
Serial.println(has);
}
void loop(){
}
PHP
<?php
$key = 'Hello';
$msg = 'secretMsg';
$encrypted = rc4_crypt($key, $msg);
echo 'encrypted b64: ', base64_encode($encrypted) ,'<br>';
echo "decrip: " , rc4_decrypt($key,rc4_crypt($key, $msg));
exit;
function rc4_crypt($key,$msg) {
$td = mcrypt_module_open('arcfour', '' , 'stream', '');
mcrypt_generic_init($td, $key, null);
$encrypted = mcrypt_generic($td, $msg);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypted;
}
function rc4_decrypt($key,$msg) {
return rc4_crypt($key,$msg);
}
?>
I had the same problem and I can confirm you that your RC4 function in Arduino is wrong, you can use this instead:
unsigned char S[256];
unsigned int i, j;
void swap(unsigned char *s, unsigned int i, unsigned int j) {
unsigned char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
/* KSA */
void rc4_init(unsigned char *key, unsigned int key_length) {
for (i = 0; i < 256; i++)
S[i] = i;
for (i = j = 0; i < 256; i++) {
j = (j + key[i % key_length] + S[i]) & 255;
swap(S, i, j);
}
i = j = 0;
}
/* PRGA */
unsigned char rc4_output() {
i = (i + 1) & 255;
j = (j + S[i]) & 255;
swap(S, i, j);
return S[(S[i] + S[j]) & 255];
}
This is the current implementation that i'm using
#define SWAP(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
class RC4
{
public:
RC4 ()
{
memset(sbox,0,256);
memset(key,0,256);
}
virtual ~RC4 ()
{
memset(sbox,0,256);
memset(key,0,256);
}
char *Encrypt(char *pszText,const char *pszKey)
{
i=0, j=0,n = 0;
ilen = (int)strlen(pszKey);
for (m = 0; m < 256; m++)
{
*(key + m)= *(pszKey + (m % ilen));
*(sbox + m) = m;
}
for (m=0; m < 256; m++)
{
n = (n + *(sbox+m) + *(key + m)) &0xff;
SWAP(*(sbox + m),*(sbox + n));
}
ilen = (int)strlen(pszText);
for (m = 0; m < ilen; m++)
{
i = (i + 1) &0xff;
j = (j + *(sbox + i)) &0xff;
SWAP(*(sbox+i),*(sbox + j));
k = *(sbox + ((*(sbox + i) + *(sbox + j)) &0xff ));
if(k == *(pszText + m))
k = 0;
*(pszText + m) ^= k;
}
return pszText;
}
char *Decrypt(char *pszText,const char *pszKey)
{
return Encrypt(pszText,pszKey) ;
}
private:
unsigned char sbox[256];
unsigned char key[256],k;
int m, n, i, j, ilen;
};
;
After a lot of trials without success I ended up with the following three codes:
Arduino code implemented RC4 (adapted from this C code) and encoding the encrypted result in Base64
PHP code that decodes base64 and decrypts RC4
HTML to test the PHP (and eventually it will be the index of ESP32 Webserver). ATTENTION! sending Base64 in the Url can be dangerous becasue the characters '+' '/' '=' can create problems, so make sure you read this post Base64 in url and the charachters that can be problematic are replaced by '.' '_' '-'
At time of writing I am using Arduino core for ESP32 version 2.0.0 consider that if you are not using this version of Base64.h there could be incompatibility (more details here)
Arduino Code
#include <stdio.h>
#include <string.h>
#include "base64.h"
typedef unsigned long ULONG;
void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len)
{
int i =0, j = 0;
char k[256] = {0};
unsigned char tmp = 0;
for (i=0;i<256;i++) {
s[i] = i;
k[i] = key[i%Len];
}
for (i=0; i<256; i++) {
j=(j+s[i]+k[i])%256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for(k=0;k<Len;k++) {
i=(i+1)%256;
j=(j+s[i])%256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t=(s[i]+s[j])%256;
Data[k] ^= s[t];
}
}
int main()
{
unsigned char s[256] = {0}; //S-box
char key[256] = "Hello";
char pData[512] = "secretMsg";
ULONG len = strlen(pData);
printf("key : %s\n", key);
printf("raw : %s\n", pData);
rc4_init(s,(unsigned char *)key,strlen(key));
rc4_crypt(s,(unsigned char *)pData,len);
printf("encrypt : %s\n", pData);
base64 b;
String encoded = b.encode((unsigned char *)pData, strlen(pData));
Serial.println(encoded);
rc4_init(s,(unsigned char *)key, strlen(key));
rc4_crypt(s,(unsigned char *)pData,len);
printf("decrypt : %s\n",pData);
return 0;
}
void setup(){
Serial.begin(115200);
main();
}
void loop(){
}
PHP CODE
<?php
function rc4_crypt($key,$msg) {
$td = mcrypt_module_open('arcfour', '' , 'stream', '');
mcrypt_generic_init($td, $key, null);
$encrypted = mcrypt_generic($td, $msg);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypted;
}
function rc4_decrypt($key,$msg) {
return rc4_crypt($key,$msg);
}
if(isset($_POST['base'])) {
$key = 'Hello';
$msg_revealed = $_POST['base'];
rc4_decrypt($key, base64_decode($msg_revealed)) //decode form base64 and decrypt
$msg = 'secretMsg'; //for testing
$encrypted = rc4_crypt($key, $msg);
echo 'encrypted b64: ', base64_encode($encrypted) ,'<br>';
echo "decrip: " , rc4_decrypt($key,rc4_crypt($key, $msg));
exit;
}
?>
HTML CODE FOR TESTING and eventually the code that will be hosted on ESP32 webserver (more info here)
<html >
<head>
<title>test Base64</title>
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<meta name='generator' content='Geany 1.36' />
</head>
<body>
<form action='https://www.yourwebsite.com/base64.php' method='post' id='downloadForm'>
<input hidden name='base' value='PASS_THE_URL_BASE64_ENCRYPTED_STRING_HERE'>
</form>
<div style='text-align: center;'><button type='button' class='btn btn-danger' onclick='sendBaseForm()'>TEST</button></div>
</body>
<script>
function sendBaseForm(){
document.getElementById('downloadForm').submit();
}
</script>
</html>

How can I get the offsets of all set bits in a bitarray?

In C, Ruby or PHP, how can I get the offsets of all set bits in an bitarray. E.g.:
Bitarray: 1 0 0 1 0
Offset: 5 4 3 2 1
Yields 2 and 5.
10001 => {1,5}
11 => {1,2}
1001001 => {1,4,7}
The most obvious solution would be to first do a reversed Find first set to know the length and then loop through the bits, saving the offset/index. However this does not seem very smart. Something like FFSR multiple times with subtraction might be better.
I came up with this. I've used binary shift operation to find out if there is binary "1" or "0". Probably you could use this code as your starting point.
#include <stdio.h>
int main()
{
int number;
int counter = 1;
printf("Please input the number to get the offsets: ");
scanf("%d", &number);
printf("The required positions of ones: ");
while ((number != 0))
{
if ((number % 2) != 0)
{
number = number >> 1;
printf("%d", counter);
}
else
{
number = number >> 1;
}
counter++;
}
return 0;
}
Here is an extended version that prints binary representation as well:
#include <stdio.h>
#include <strings.h>
char* rev(char* str);
int main()
{
int number, temp;
int counter = 1;
char str[32] = "";
printf("Please input the number to get the offsets: ");
scanf("%d", &number);
temp = number;
printf("Binary representation: ");
while ((temp != 0))
{
if ((temp % 2) != 0)
{
temp = temp >> 1;
strncat(str, "1", 1);
}
else
{
temp = temp >> 1;
strncat(str, "0", 1);
}
}
printf("%s", rev(str));
printf("\nThe required positions of ones: ");
while ((number != 0))
{
if ((number % 2) != 0)
{
number = number >> 1;
printf("%d", counter);
}
else
{
number = number >> 1;
}
counter++;
}
getch();
getch();
return 0;
}
char* rev(char* str)
{
int end= strlen(str) - 1;
int start = 0;
while( start<end )
{
str[start] ^= str[end];
str[end] ^= str[start];
str[start]^= str[end];
++start;
--end;
}
return str;
}

Increment individual IPs from IPv6 string (php)

What is a simple, elegant way to list the first x number of IPv6 IPs from a IPv6 string.
For example,
listIPs("2600:f333:10:c000::0", 4)
echos
2600:f333:10:c000::1
2600:f333:10:c000::2
2600:f333:10:c000::3
2600:f333:10:c000::4
Here's a sample of code that may have worked for IPv4, as it converted to int:
$input = "2600:f333:10:c000::/51";
$max = 4;
list($block, $cidr) = explode("/", $input);
$first = inet_pton( $block );
echo inet_ntop($first) . "\n";
for ($i = 1; $i < $max; $i++) {
//todo: die if it has exceeded block size based on $cidr
echo inet_ntop($first + $i) . "\n"; //doesn't work, packed binary?
}
Here's an example program written in C (since I don't know C++). It's fairly fast, but I'm not really happy with it. Maybe someone can help me improve it.
Edit: Obviously, I wrote this before it was turned into a PHP-only question. Turning this into PHP is left as an exercise to the reader (ew).
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
/*
* Syntax: ./ipv6_list <ip>/<cidr-prefix>
*/
int main(int argc, char **argv) {
uint8_t start[16];
uint8_t address[16];
uint8_t mask[16] = { 0 };
uint8_t prefix = 128;
char *prefix_location;
int i;
/* This is the octet that, when changed, will result in <IP> & <mask> != <start IP> */
int mask_check_octet = 0;
if(argc != 2)
return 1;
/* Find prefix */
if((prefix_location = strstr(argv[1], "/")) != NULL) {
char *prefix_search = prefix_location + 1;
char *prefix_remaining;
long prefix_test;
if(!isdigit(*prefix_search))
return 2;
errno = 0;
prefix_test = strtol(prefix_search, &prefix_remaining, 10);
if(errno == ERANGE || prefix_test < 0 || prefix_test > 128 || strcmp(prefix_remaining, "") != 0)
return 2;
prefix = (uint8_t)prefix_test;
*prefix_location = '\0'; /* So we can just pass argv[1] into inet_pton(3) */
}
/* Convert prefix into mask */
for(i = 0; i < 16; i++) {
if(prefix == 0)
break;
mask_check_octet = i;
if(prefix < 8) {
mask[i] = ~((1 << (8 - prefix)) - 1);
break;
}
else
mask[i] = UINT8_MAX;
prefix -= 8;
}
/* Find address */
if(inet_pton(AF_INET6, argv[1], start) != 1)
return 3;
/* Start at the beginning of the network */
for(i = 0; i < 16; i++) {
start[i] &= mask[i];
address[i] = start[i];
}
/* Iterate */
while((address[mask_check_octet] & mask[mask_check_octet]) == start[mask_check_octet]) {
char address_str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, address, address_str, sizeof(address_str));
printf("%s\n", address_str);
/* Add one to the address */
for(i = 15; i >= 0; i--) {
if(address[i] != UINT8_MAX)
break;
}
address[i]++;
for(i++; i < 16; i++)
address[i] = 0;
};
return 0;
}
You can use standard shell commands to limit its output (or just modify the while loop):
nfontes#brioche:~$ ./ipv6_list '2607:fc50:0:d00::0/106' | head -n 200
2607:fc50:0:d00::
2607:fc50:0:d00::1
2607:fc50:0:d00::2
2607:fc50:0:d00::3
2607:fc50:0:d00::4
2607:fc50:0:d00::5
2607:fc50:0:d00::6
2607:fc50:0:d00::7
2607:fc50:0:d00::8
2607:fc50:0:d00::9
2607:fc50:0:d00::a
2607:fc50:0:d00::b
2607:fc50:0:d00::c
2607:fc50:0:d00::d
2607:fc50:0:d00::e
[...]
2607:fc50:0:d00::c0
2607:fc50:0:d00::c1
2607:fc50:0:d00::c2
2607:fc50:0:d00::c3
2607:fc50:0:d00::c4
2607:fc50:0:d00::c5
2607:fc50:0:d00::c6
2607:fc50:0:d00::c7
Something similar (in PHP). It takes an IPv4/IPv6 address and increments it by given value:
// Takes an IPv4/IPv6 address in string format, and increments it by given value
function incrementIp($ip, $increment)
{
$addr = inet_pton ( $ip );
for ( $i = strlen ( $addr ) - 1; $increment > 0 && $i >= 0; --$i )
{
$val = ord($addr[$i]) + $increment;
$increment = $val / 256;
$addr[$i] = chr($val % 256);
}
return inet_ntop ( $addr );
}

CRC 16 -DECT with poly x^16 + x^10 + x^8 + x^7 + x^3 + 1

believe me I have tried to code this, tried Google, and haven't had any luck.
I'm trying to implement a CRC16 using this poly
x^16 + x^10 + x^8 + x^7 + x^3 + 1
using the C language. Since I understand PHP better I'm trying to get a function going, but I'm not getting the right answer of 28713. This code is generating a CRC of 32713.
function crc16($string,$crc=0) {
for ( $x=0; $x<strlen( $string ); $x++ ) {
$crc = $crc ^ ord( $string[$x] );
echo $crc.'<br />';
for ($y = 0; $y < 8 ; $y++) {
if ( ($crc & 0x0001) == 0x0001 ) $crc = ( ($crc >> 1 ) ^ 0x10589 );
else $crc = $crc >> 1;
}
}
return $crc;
}
echo 'CRC:'.crc16('10100011');
Please I beg anyone to give a hand with this..thanks in advance.
Some CRCs are defined to process the bits from each byte from MSB to LSB, and some are defined to process bits from LSB to MSB (the latter is generally the order which is described as "reflected" and uses a reversed polynomial). Your code puts new bits in at the LSB end of the CRC and shifts right, which is suitable for a reflected CRC, but CRC-16-DECT appears to be one of the non-reflected ones.
Your input of "10100011" suggests binary, but is being processed as an 8-byte ASCII string.
To see what happens when treating 10100011 as binary instead, and working from MSB first, here's a hand calculation (as 8 bits of input doesn't require very much effort):
polynomial coefficients
|
| 10100010 <--- quotient (irrelevant)
v __________
10000010110001001 ) 10100011 <-------- input
^ 10000010110001001
-----------------
= 100001110001001
^ 10000010110001001
-----------------
= 101110101101
^ 10000010110001001
-----------------
remainder (CRC) -----> = 111000000101001
= 0x7029 = 28713
So treating the input as binary and working MSB first is the right thing to do.
Here is some C code to do the job (as I'm not really into PHP, and ultimately you want C code anyway):
#include <stdio.h>
#include <stdint.h>
static uint16_t crc16(const uint8_t *data, size_t len)
{
size_t i, j;
uint16_t crc = 0;
for (i = 0; i < len; i++) {
crc ^= (data[i] << 8); /* data at top end, not bottom */
for (j = 0; j < 8; j++) {
if ((crc & 0x8000) == 0x8000) /* top bit, not bottom */
crc = (crc << 1) ^ 0x0589; /* shift left, not right */
else
crc <<= 1; /* shift left, not right */
}
}
return crc;
}
int main(void)
{
const uint8_t in[] = { 0xa3 }; /* = 10100011 in binary */
uint16_t crc = crc16(in, sizeof(in));
printf("%u (0x%x)\n", crc, crc);
return 0;
}
Result:
$ gcc -Wall -o crc16 crc16.c
$ ./crc16
28713 (0x7029)
$
Try changing 0x10589 to 0xA001:
function crc16($string,$crc=0) {
for ( $x=0; $x<strlen( $string ); $x++ ) {
$crc = $crc ^ ord( $string[$x] );
for ($y = 0; $y < 8; $y++) {
if ( ($crc & 0x0001) == 0x0001 ) $crc = ( ($crc >> 1 ) ^ 0xA001 );
else $crc = $crc >> 1;
}
}
return $crc;
}
This code works everytime, but I'm not exactly understanding what's going on.
char *MakeCRC(char *BitString)
{
static char Res[17]; // CRC Result
char CRC[16];
int i;
char DoInvert;
for (i=0; i<16; ++i) CRC[i] = 0; // Init before calculation
for (i=0; i<strlen(BitString); ++i)
{
DoInvert = ('1'==BitString[i]) ^ CRC[15]; // XOR required?
CRC[15] = CRC[14];
CRC[14] = CRC[13];
CRC[13] = CRC[12];
CRC[12] = CRC[11];
CRC[11] = CRC[10];
CRC[10] = CRC[9] ^ DoInvert;
CRC[9] = CRC[8];
CRC[8] = CRC[7] ^ DoInvert;
CRC[7] = CRC[6] ^ DoInvert;
CRC[6] = CRC[5];
CRC[5] = CRC[4];
CRC[4] = CRC[3];
CRC[3] = CRC[2] ^ DoInvert;
CRC[2] = CRC[1];
CRC[1] = CRC[0];
CRC[0] = DoInvert;
}
for (i=0; i<16; ++i) Res[15-i] = CRC[i] ? '1' : '0'; // Convert binary to ASCII
Res[16] = 0; // Set string terminator
return(Res);
}
// A simple test driver:
#include <stdio.h>
int main()
{
char *Data, *Result; // Declare two strings
Data = "1101000101000111";
Result = MakeCRC(Data); // Calculate CRC
printf("CRC of [%s] is [%s] with P=[10000010110001001]\n", Data, Result);
return(0);
}

Categories