mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-17 05:22:31 -04:00
added method for removign signatures in a PGP certificate, and a test program to test it. Not yet plugged in into RS
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4831 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
7c11c6efac
commit
4422d6557b
6 changed files with 552 additions and 2 deletions
|
@ -477,6 +477,8 @@ HEADERS += util/folderiterator.h \
|
||||||
util/rswin.h \
|
util/rswin.h \
|
||||||
util/rsrandom.h \
|
util/rsrandom.h \
|
||||||
util/pugiconfig.h \
|
util/pugiconfig.h \
|
||||||
|
util/radix64.h \
|
||||||
|
util/pgpkey.h \
|
||||||
util/pugixml.h
|
util/pugixml.h
|
||||||
|
|
||||||
SOURCES += dbase/cachestrapper.cc \
|
SOURCES += dbase/cachestrapper.cc \
|
||||||
|
@ -616,6 +618,7 @@ SOURCES += util/folderiterator.cc \
|
||||||
util/rsversion.cc \
|
util/rsversion.cc \
|
||||||
util/rswin.cc \
|
util/rswin.cc \
|
||||||
util/rsrandom.cc \
|
util/rsrandom.cc \
|
||||||
|
util/pgpkey.cc \
|
||||||
util/pugixml.cc
|
util/pugixml.cc
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,14 @@ DHT_TOP_DIR = ../../../../libbitdht/src
|
||||||
include $(RS_TOP_DIR)/tests/scripts/config.mk
|
include $(RS_TOP_DIR)/tests/scripts/config.mk
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
TESTOBJ = netsetup_test.o random_test.o memory_management_test.o
|
TESTOBJ = netsetup_test.o random_test.o memory_management_test.o pgpkey_test.o
|
||||||
TESTS = netsetup_test random_test memory_management_test
|
TESTS = netsetup_test random_test memory_management_test pgpkey_test
|
||||||
|
|
||||||
all: tests
|
all: tests
|
||||||
|
|
||||||
|
pgpkey_test: pgpkey_test.o
|
||||||
|
$(CC) $(CFLAGS) -o pgpkey_test pgpkey_test.o $(LIBS)
|
||||||
|
|
||||||
netsetup_test: netsetup_test.o
|
netsetup_test: netsetup_test.o
|
||||||
$(CC) $(CFLAGS) -o netsetup_test netsetup_test.o $(LIBS)
|
$(CC) $(CFLAGS) -o netsetup_test netsetup_test.o $(LIBS)
|
||||||
|
|
||||||
|
|
59
libretroshare/src/tests/general/pgpkey_test.cc
Normal file
59
libretroshare/src/tests/general/pgpkey_test.cc
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifdef LINUX
|
||||||
|
#include <fenv.h>
|
||||||
|
#endif
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "util/utest.h"
|
||||||
|
#include "util/pgpkey.h"
|
||||||
|
|
||||||
|
INITTEST();
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
#ifdef LINUX
|
||||||
|
feenableexcept(FE_INVALID) ;
|
||||||
|
feenableexcept(FE_DIVBYZERO) ;
|
||||||
|
#endif
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(argc < 2)
|
||||||
|
{
|
||||||
|
std::cerr << argv[0] << ": test gpg certificate cleaning method. " << std::endl;
|
||||||
|
std::cerr << " Usage: " << argv[0] << " certificate.asc" << std::endl;
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(argv[1],"r") ;
|
||||||
|
|
||||||
|
if(f == NULL)
|
||||||
|
throw std::runtime_error(std::string("Could not open file ") + argv[1]) ;
|
||||||
|
|
||||||
|
std::string cert ;
|
||||||
|
int c ;
|
||||||
|
|
||||||
|
while((c = getc(f) ) != EOF)
|
||||||
|
cert += (char)c ;
|
||||||
|
|
||||||
|
std::cerr << "got this certificate: " << std::endl;
|
||||||
|
std::cerr << cert << std::endl;
|
||||||
|
|
||||||
|
std::cerr << "Calling cert simplification code..." << std::endl;
|
||||||
|
std::string cleaned_key ;
|
||||||
|
|
||||||
|
PGPKeyManagement::createMinimalKey(cert,cleaned_key) ;
|
||||||
|
|
||||||
|
std::cerr << "Minimal key produced: " << std::endl;
|
||||||
|
std::cerr << cleaned_key << std::endl;
|
||||||
|
FINALREPORT("pgpkey_test");
|
||||||
|
exit(TESTRESULT());
|
||||||
|
}
|
||||||
|
catch(std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception never handled: " << e.what() << std::endl ;
|
||||||
|
return 1 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
227
libretroshare/src/util/pgpkey.cc
Normal file
227
libretroshare/src/util/pgpkey.cc
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <util/radix64.h>
|
||||||
|
#include "pgpkey.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#define PGP_PACKET_TAG_PUBLIC_KEY 6
|
||||||
|
#define PGP_PACKET_TAG_USER_ID 13
|
||||||
|
#define PGP_PACKET_TAG_SIGNATURE 2
|
||||||
|
|
||||||
|
#define PGP_CRC24_INIT 0xB704CEL
|
||||||
|
#define PGP_CRC24_POLY 0x1864CFBL
|
||||||
|
|
||||||
|
#define PGP_CERTIFICATE_START_STRING "-----BEGIN PGP PUBLIC KEY BLOCK-----"
|
||||||
|
#define PGP_CERTIFICATE_END_STRING "-----END PGP PUBLIC KEY BLOCK-----"
|
||||||
|
//
|
||||||
|
// All size are big endian
|
||||||
|
// MPI: 2 bytes size (length in bits) + string of octets
|
||||||
|
//
|
||||||
|
bool PGPKeyManagement::createMinimalKey(const std::string& pgp_certificate,std::string& cleaned_certificate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 0 - Extract Radix64 portion of the certificate
|
||||||
|
//
|
||||||
|
int n = pgp_certificate.length() ;
|
||||||
|
int i=0 ;
|
||||||
|
std::string version_string = "" ;
|
||||||
|
|
||||||
|
while(i < n && pgp_certificate[i] != '\n') ++i ; // remove first part -----BEGIN PGP CERTIFICATE-----
|
||||||
|
++i ;
|
||||||
|
while(i < n && pgp_certificate[i] != '\n') version_string += pgp_certificate[i++] ; // remove first part Version: [fdfdfdf]
|
||||||
|
++i ;
|
||||||
|
while(i < n && pgp_certificate[i] != '\n') ++i ; // remove blank line
|
||||||
|
|
||||||
|
++i ;
|
||||||
|
|
||||||
|
int j=n-1 ;
|
||||||
|
|
||||||
|
while(j>0 && pgp_certificate[j] != '=' && j>=i) --j ;
|
||||||
|
|
||||||
|
std::string radix_cert = pgp_certificate.substr(i,j-i) ;
|
||||||
|
|
||||||
|
std::cerr << "extracted radix cert: " << std::endl;
|
||||||
|
std::cerr << radix_cert ;
|
||||||
|
|
||||||
|
// 1 - Convert armored key into binary key
|
||||||
|
//
|
||||||
|
|
||||||
|
char *keydata = NULL ;
|
||||||
|
size_t len = 0 ;
|
||||||
|
|
||||||
|
Radix64::decode(radix_cert,keydata,len) ;
|
||||||
|
|
||||||
|
unsigned char *data = (unsigned char *)keydata ;
|
||||||
|
|
||||||
|
std::cerr << "Total size: " << len << std::endl;
|
||||||
|
|
||||||
|
uint8_t packet_tag;
|
||||||
|
uint32_t packet_length ;
|
||||||
|
|
||||||
|
// 2 - parse key data, only keep public key data, user id and self-signature.
|
||||||
|
|
||||||
|
bool public_key=false ;
|
||||||
|
bool own_signature=false ;
|
||||||
|
bool user_id=false ;
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ;
|
||||||
|
|
||||||
|
std::cerr << "Header:" << std::endl;
|
||||||
|
std::cerr << " Packet tag: " << (int)packet_tag << std::endl;
|
||||||
|
std::cerr << " Packet length: " << packet_length << std::endl;
|
||||||
|
|
||||||
|
data += packet_length ;
|
||||||
|
|
||||||
|
if(packet_tag == PGP_PACKET_TAG_PUBLIC_KEY)
|
||||||
|
public_key = true ;
|
||||||
|
if(packet_tag == PGP_PACKET_TAG_USER_ID)
|
||||||
|
user_id = true ;
|
||||||
|
if(packet_tag == PGP_PACKET_TAG_SIGNATURE)
|
||||||
|
own_signature = true ;
|
||||||
|
|
||||||
|
if(public_key && own_signature && user_id)
|
||||||
|
break ;
|
||||||
|
|
||||||
|
if( (uint64_t)data - (uint64_t)keydata >= len )
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string outstring ;
|
||||||
|
Radix64::encode(keydata,(uint64_t)data - (uint64_t)keydata,outstring) ;
|
||||||
|
|
||||||
|
uint32_t crc = compute24bitsCRC((unsigned char *)keydata,(uint64_t)data - (uint64_t)keydata) ;
|
||||||
|
|
||||||
|
unsigned char tmp[3] = { (crc >> 16) & 0xff, (crc >> 8) & 0xff, crc & 0xff } ;
|
||||||
|
std::string crc_string ;
|
||||||
|
Radix64::encode((const char *)tmp,3,crc_string) ;
|
||||||
|
|
||||||
|
std::cerr << "After signature pruning: " << std::endl;
|
||||||
|
std::cerr << outstring << std::endl;
|
||||||
|
|
||||||
|
cleaned_certificate = std::string(PGP_CERTIFICATE_START_STRING) + "\n" + version_string + "\n\n" ;
|
||||||
|
|
||||||
|
for(uint32_t i=0;i<outstring.length();i+=64)
|
||||||
|
cleaned_certificate += outstring.substr(i,64) + "\n" ;
|
||||||
|
|
||||||
|
cleaned_certificate += "=" + crc_string + "\n" ;
|
||||||
|
cleaned_certificate += std::string(PGP_CERTIFICATE_END_STRING) + "\n" ;
|
||||||
|
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
catch(std::exception& e)
|
||||||
|
{
|
||||||
|
cleaned_certificate = "" ;
|
||||||
|
std::cerr << "Certificate cleaning failed: " << e.what() << std::endl;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PGPKeyManagement::compute24bitsCRC(unsigned char *octets, size_t len)
|
||||||
|
{
|
||||||
|
long crc = PGP_CRC24_INIT;
|
||||||
|
int i;
|
||||||
|
while (len--) {
|
||||||
|
crc ^= (*octets++) << 16;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
crc <<= 1;
|
||||||
|
if (crc & 0x1000000)
|
||||||
|
crc ^= PGP_CRC24_POLY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc & 0xFFFFFFL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t PGPKeyParser::read_KeyID(unsigned char *& data)
|
||||||
|
{
|
||||||
|
uint64_t val = 0 ;
|
||||||
|
|
||||||
|
val |= uint64_t( *data ) << 56 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 48 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 40 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 32 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 24 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 16 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 8 ; ++data ;
|
||||||
|
val |= uint64_t( *data ) << 0 ; ++data ;
|
||||||
|
|
||||||
|
return val ;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PGPKeyParser::read_125Size(unsigned char *& data)
|
||||||
|
{
|
||||||
|
uint8_t b1 = *data ;
|
||||||
|
++data ;
|
||||||
|
|
||||||
|
if(b1 < 192)
|
||||||
|
return b1 ;
|
||||||
|
|
||||||
|
uint8_t b2 = *data ;
|
||||||
|
|
||||||
|
if(b1 < 224)
|
||||||
|
return ((b1-192) << 8) + b2 + 192 ;
|
||||||
|
|
||||||
|
if(b1 != 0xff)
|
||||||
|
throw std::runtime_error("GPG parsing error") ;
|
||||||
|
|
||||||
|
uint8_t b3 = *data ; ++data ;
|
||||||
|
uint8_t b4 = *data ; ++data ;
|
||||||
|
uint8_t b5 = *data ; ++data ;
|
||||||
|
|
||||||
|
return (b2 << 24) | (b3 << 16) | (b4 << 8) | b5 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PGPKeyParser::read_partialBodyLength(unsigned char *& data)
|
||||||
|
{
|
||||||
|
uint8_t b1 =*data ;
|
||||||
|
++data ;
|
||||||
|
|
||||||
|
return 1 << (b1 & 0x1F) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PGPKeyParser::read_packetHeader(unsigned char *& data,uint8_t& packet_tag,uint32_t& packet_length)
|
||||||
|
{
|
||||||
|
uint8_t b1 = *data ;
|
||||||
|
++data ;
|
||||||
|
|
||||||
|
bool new_format = b1 & 0x40 ;
|
||||||
|
|
||||||
|
if(new_format)
|
||||||
|
{
|
||||||
|
std::cerr << "Packet is in new format" << std::endl;
|
||||||
|
packet_tag = b1 & 0x3f ;
|
||||||
|
packet_length = read_125Size(data) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Packet is in old format" << std::endl;
|
||||||
|
uint8_t length_type = b1 & 0x03 ;
|
||||||
|
packet_tag = (b1 & 0x3c) >> 2 ;
|
||||||
|
|
||||||
|
int length_size ;
|
||||||
|
switch(length_type)
|
||||||
|
{
|
||||||
|
case 0: length_size = 1 ;
|
||||||
|
break ;
|
||||||
|
case 1: length_size = 2 ;
|
||||||
|
break ;
|
||||||
|
case 2: length_size = 4 ;
|
||||||
|
break ;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unhandled length type!") ;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_length = 0 ;
|
||||||
|
for(int k=0;k<length_size;++k)
|
||||||
|
{
|
||||||
|
packet_length <<= 8 ;
|
||||||
|
packet_length |= *data ;
|
||||||
|
++data ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
79
libretroshare/src/util/pgpkey.h
Normal file
79
libretroshare/src/util/pgpkey.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/****************************************************************
|
||||||
|
* RetroShare is distributed under the following license:
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Cyril Soler <csoler@users.sourceforge.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// refer to RFC4880 specif document for loading GPG public keys:
|
||||||
|
//
|
||||||
|
// 11.1: transferable public keys
|
||||||
|
// Global structure of transferable public keys
|
||||||
|
//
|
||||||
|
// - one public key packet (see 12.2)
|
||||||
|
// - zero or more revocation signatures (See signature type 5.2.1 for key signature types)
|
||||||
|
//
|
||||||
|
// - user certification signatures (0x10 or 0x13)
|
||||||
|
//
|
||||||
|
// - 5.2.2: Signature format packet
|
||||||
|
// - 5.2.3.1: signature subpacket specification
|
||||||
|
//
|
||||||
|
// - 4.3: packet tags (1 byte)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// This class handles GPG keys. For now we only clean them from signatures, but
|
||||||
|
// in the future, we might cache them to avoid unnecessary calls to gpgme.
|
||||||
|
//
|
||||||
|
class PGPKeyManagement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Create a minimal key, removing all signatures and third party info.
|
||||||
|
// Input: a clean PGP certificate (starts with "----BEGIN",
|
||||||
|
// ends with "-----END PGP PUBLIC KEY BLOCK-----"
|
||||||
|
// Output: the same certificate without signatures.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
//
|
||||||
|
// true if the certificate cleaning succeeded
|
||||||
|
// false otherwise.
|
||||||
|
//
|
||||||
|
static bool createMinimalKey(const std::string& pgp_certificate,std::string& cleaned_certificate) ;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Computes the 24 bits CRC checksum necessary to all PGP data.
|
||||||
|
//
|
||||||
|
static uint32_t compute24bitsCRC(unsigned char *data,size_t len) ;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class handles the parsing of PGP packet headers under various (old and new) formats.
|
||||||
|
//
|
||||||
|
class PGPKeyParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static uint64_t read_KeyID(unsigned char *& data) ;
|
||||||
|
static uint32_t read_125Size(unsigned char *& data) ;
|
||||||
|
static uint32_t read_partialBodyLength(unsigned char *& data) ;
|
||||||
|
static void read_packetHeader(unsigned char *& data,uint8_t& packet_tag,uint32_t& packet_length) ;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
179
libretroshare/src/util/radix64.h
Normal file
179
libretroshare/src/util/radix64.h
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Radix64
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void decode(const std::string& buffer,char *& out, size_t& len)
|
||||||
|
{
|
||||||
|
char val;
|
||||||
|
int c = 0, c2;/* init c because gcc is not clever
|
||||||
|
enough for the continue */
|
||||||
|
int idx;
|
||||||
|
size_t buffer_pos = 0;
|
||||||
|
|
||||||
|
radix64_init();
|
||||||
|
|
||||||
|
std::vector<char> buf ;
|
||||||
|
idx = 0;
|
||||||
|
val = 0;
|
||||||
|
|
||||||
|
for (buffer_pos = 0; buffer_pos < buffer.length(); buffer_pos++)
|
||||||
|
{
|
||||||
|
c = buffer[buffer_pos];
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
|
||||||
|
continue;
|
||||||
|
else if (c == '=')
|
||||||
|
{
|
||||||
|
/* pad character: stop */
|
||||||
|
/* some mailers leave quoted-printable
|
||||||
|
* encoded characters so we try to
|
||||||
|
* workaround this */
|
||||||
|
if (buffer_pos + 2 < buffer.length())
|
||||||
|
{
|
||||||
|
int cc1, cc2, cc3;
|
||||||
|
cc1 = buffer[buffer_pos];
|
||||||
|
cc2 = buffer[buffer_pos + 1];
|
||||||
|
cc3 = buffer[buffer_pos + 2];
|
||||||
|
|
||||||
|
if (isxdigit((unsigned char)cc1) && isxdigit((unsigned char)cc2) && strchr("=\n\r\t ", cc3))
|
||||||
|
{
|
||||||
|
/* well it seems to be the case -
|
||||||
|
* adjust */
|
||||||
|
c =
|
||||||
|
isdigit((unsigned char)cc1) ? (cc1 -
|
||||||
|
'0')
|
||||||
|
: (toupper((unsigned char)cc1) - 'A' + 10);
|
||||||
|
c <<= 4;
|
||||||
|
c |=
|
||||||
|
isdigit((unsigned char)cc2) ? (cc2 -
|
||||||
|
'0')
|
||||||
|
: (toupper((unsigned char)cc2) - 'A' + 10);
|
||||||
|
buffer_pos += 2;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == 1)
|
||||||
|
buf.push_back(val) ;// buf[n++] = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ((c = asctobin()[(c2 = c)]) == 255)
|
||||||
|
{
|
||||||
|
/* invalid radix64 character %02x skipped\n", c2; */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
val = c << 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
val |= (c >> 4) & 3;
|
||||||
|
buf.push_back(val);//buf[n++] = val;
|
||||||
|
val = (c << 4) & 0xf0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
val |= (c >> 2) & 15;
|
||||||
|
buf.push_back(val);//buf[n++] = val;
|
||||||
|
val = (c << 6) & 0xc0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
val |= c & 0x3f;
|
||||||
|
buf.push_back(val);//buf[n++] = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx = (idx + 1) % 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = idx;
|
||||||
|
|
||||||
|
len = buf.size() ;
|
||||||
|
out = new char[len] ;
|
||||||
|
|
||||||
|
memcpy(out,buf.data(),len) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* create a radix64 encoded string.
|
||||||
|
*/
|
||||||
|
static void encode(const char *data,int len,std::string& out_string)
|
||||||
|
{
|
||||||
|
char *buffer, *p;
|
||||||
|
|
||||||
|
radix64_init();
|
||||||
|
|
||||||
|
int size = (len + 2) / 3 * 4 +1;
|
||||||
|
buffer = p = new char[size] ;
|
||||||
|
|
||||||
|
for (; len >= 3; len -= 3, data += 3)
|
||||||
|
{
|
||||||
|
*p++ = bintoasc()[(data[0] >> 2) & 077];
|
||||||
|
*p++ =
|
||||||
|
bintoasc()[
|
||||||
|
(((data[0] << 4) & 060) |
|
||||||
|
((data[1] >> 4) & 017)) & 077];
|
||||||
|
*p++ =
|
||||||
|
bintoasc()[
|
||||||
|
(((data[1] << 2) & 074) |
|
||||||
|
((data[2] >> 6) & 03)) & 077];
|
||||||
|
*p++ = bintoasc()[data[2] & 077];
|
||||||
|
}
|
||||||
|
if (len == 2)
|
||||||
|
{
|
||||||
|
*p++ = bintoasc()[(data[0] >> 2) & 077];
|
||||||
|
*p++ =
|
||||||
|
bintoasc()[
|
||||||
|
(((data[0] << 4) & 060) |
|
||||||
|
((data[1] >> 4) & 017)) & 077];
|
||||||
|
*p++ = bintoasc()[((data[1] << 2) & 074)];
|
||||||
|
*p++ = '=' ;
|
||||||
|
}
|
||||||
|
else if (len == 1)
|
||||||
|
{
|
||||||
|
*p++ = bintoasc()[(data[0] >> 2) & 077];
|
||||||
|
*p++ = bintoasc()[(data[0] << 4) & 060];
|
||||||
|
*p++ = '=' ;
|
||||||
|
*p++ = '=' ;
|
||||||
|
}
|
||||||
|
//*p = 0;
|
||||||
|
out_string = std::string(buffer,p-buffer) ;
|
||||||
|
delete[] buffer ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline char *bintoasc() { static char bta[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; return bta ; }
|
||||||
|
static inline char *asctobin() { static char s[256]; return s ; } /* runtime radix64_initd */
|
||||||
|
static int& is_radix64_initd() { static int is_inited = false ; return is_inited ; }
|
||||||
|
|
||||||
|
/* hey, guess what: this is a read-only table.
|
||||||
|
* we don't _care_ if multiple threads get to initialise it
|
||||||
|
* at the same time, _except_ that is_radix64_initd=1 _must_
|
||||||
|
* be done at the end...
|
||||||
|
*/
|
||||||
|
static bool radix64_init()
|
||||||
|
{
|
||||||
|
if (is_radix64_initd())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
/* build the helpapr_table_t for radix64 to bin conversion */
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
asctobin()[i] = 255; /* used to detect invalid characters */
|
||||||
|
for (s = bintoasc(), i = 0; *s; s++, i++)
|
||||||
|
asctobin()[(int)*s] = i;
|
||||||
|
|
||||||
|
is_radix64_initd() = 1;
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue