--- /dev/null
+/*
+ * Based on code parts from pegwit program written by George Barwood.
+ * This code is in the public domain; do with it what you wish.
+ *
+ **/
+#if defined(__DEBUG__)
+#include <cstdio>
+#endif
+
+#include "string.h"
+#include "stdlib.h"
+#include "CP_RSA.h"
+
+
+static vlong modexp( const vlong & x, const vlong & e, const vlong & m ); // m must be odd
+static vlong gcd( const vlong &X, const vlong &Y ); // greatest common denominator
+static vlong modinv( const vlong &a, const vlong &m ); // modular inverse
+
+// VLONG.CPP -----------------------------------
+
+class flex_unit // Provides storage allocation and index checking
+{
+public:
+
+ unsigned * a; // array of units
+ unsigned z; // units allocated
+
+ unsigned n; // used units (read-only)
+ flex_unit();
+ ~flex_unit();
+ void clear(); // set n to zero
+ unsigned get( unsigned i ) const; // get ith unsigned
+ void set( unsigned i, unsigned x ); // set ith unsigned
+ void reserve( unsigned x ); // storage hint
+
+ // Time critical routine
+ void fast_mul( flex_unit &x, flex_unit &y, unsigned n );
+};
+
+class vlong_value : public flex_unit
+{
+ public:
+ unsigned share; // share count, used by vlong to delay physical copying
+ int is_zero() const;
+ int test( unsigned i ) const;
+ unsigned bits() const;
+ int cf( vlong_value& x ) const;
+ void shl();
+ void shr();
+ void shr( unsigned n );
+ void add( vlong_value& x );
+ void subtract( vlong_value& x );
+ void init( unsigned x );
+ void copy( vlong_value& x );
+ operator unsigned(); // Unsafe conversion to unsigned
+ vlong_value();
+ void mul( vlong_value& x, vlong_value& y );
+ void divide( vlong_value& x, vlong_value& y, vlong_value& rem );
+};
+
+unsigned flex_unit::get( unsigned i ) const
+{
+ if ( i >= n ) return 0;
+ return a[i];
+}
+
+void flex_unit::clear()
+{
+ n = 0;
+}
+
+flex_unit::flex_unit()
+{
+ z = 0;
+ a = 0;
+ n = 0;
+}
+
+flex_unit::~flex_unit()
+{
+ unsigned i=z;
+ while (i) { i-=1; a[i] = 0; } // burn
+ delete [] a;
+}
+
+void flex_unit::reserve( unsigned x )
+{
+ if (x > z)
+ {
+ unsigned * na = new unsigned[x];
+ for (unsigned i=0;i<n;i+=1) na[i] = a[i];
+ delete [] a;
+ a = na;
+ z = x;
+ }
+}
+
+void flex_unit::set( unsigned i, unsigned x )
+{
+ if ( i < n )
+ {
+ a[i] = x;
+ if (x==0) while (n && a[n-1]==0) n-=1; // normalise
+ }
+ else if ( x )
+ {
+ reserve(i+1);
+ for (unsigned j=n;j<i;j+=1) a[j] = 0;
+ a[i] = x;
+ n = i+1;
+ }
+}
+
+// Macros for doing double precision multiply
+#define BPU ( 8*sizeof(unsigned) ) // Number of bits in an unsigned
+#define lo(x) ( (x) & ((1<<(BPU/2))-1) ) // lower half of unsigned
+#define hi(x) ( (x) >> (BPU/2) ) // upper half
+#define lh(x) ( (x) << (BPU/2) ) // make upper half
+
+void flex_unit::fast_mul( flex_unit &x, flex_unit &y, unsigned keep )
+{
+ // *this = (x*y) % (2**keep)
+ unsigned i,j,limit = (keep+BPU-1)/BPU; // size of result in words
+ reserve(limit); for (i=0; i<limit; i+=1) a[i] = 0;
+ unsigned min = x.n; if (min>limit) min = limit;
+ for (i=0; i<min; i+=1)
+ {
+ unsigned m = x.a[i];
+ unsigned c = 0; // carry
+ unsigned min = i+y.n; if (min>limit) min = limit;
+ for ( j=i; j<min; j+=1 )
+ {
+ // This is the critical loop
+ // Machine dependent code could help here
+ // c:a[j] = a[j] + c + m*y.a[j-i];
+ unsigned w, v = a[j], p = y.a[j-i];
+ v += c; c = ( v < c );
+ w = lo(p)*lo(m); v += w; c += ( v < w );
+ w = lo(p)*hi(m); c += hi(w); w = lh(w); v += w; c += ( v < w );
+ w = hi(p)*lo(m); c += hi(w); w = lh(w); v += w; c += ( v < w );
+ c += hi(p) * hi(m);
+ a[j] = v;
+ }
+ while ( c && j<limit )
+ {
+ a[j] += c;
+ c = a[j] < c;
+ j += 1;
+ }
+ }
+
+ // eliminate unwanted bits
+ keep %= BPU; if (keep) a[limit-1] &= (1<<keep)-1;
+
+ // calculate n
+ while (limit && a[limit-1]==0) limit-=1;
+ n = limit;
+};
+
+vlong_value::operator unsigned()
+{
+ return get(0);
+}
+
+int vlong_value::is_zero() const
+{
+ return n==0;
+}
+
+int vlong_value::test( unsigned i ) const
+{ return ( get(i/BPU) & (1<<(i%BPU)) ) != 0; }
+
+unsigned vlong_value::bits() const
+{
+ unsigned x = n*BPU;
+ while (x && test(x-1)==0) x -= 1;
+ return x;
+}
+
+int vlong_value::cf( vlong_value& x ) const
+{
+ if ( n > x.n ) return +1;
+ if ( n < x.n ) return -1;
+ unsigned i = n;
+ while (i)
+ {
+ i -= 1;
+ if ( get(i) > x.get(i) ) return +1;
+ if ( get(i) < x.get(i) ) return -1;
+ }
+ return 0;
+}
+
+void vlong_value::shl()
+{
+ unsigned carry = 0;
+ unsigned N = n; // necessary, since n can change
+ for (unsigned i=0;i<=N;i+=1)
+ {
+ unsigned u = get(i);
+ set(i,(u<<1)+carry);
+ carry = u>>(BPU-1);
+ }
+}
+
+void vlong_value::shr()
+{
+ unsigned carry = 0;
+ unsigned i=n;
+ while (i)
+ {
+ i -= 1;
+ unsigned u = get(i);
+ set(i,(u>>1)+carry);
+ carry = u<<(BPU-1);
+ }
+}
+
+void vlong_value::shr( unsigned x )
+{
+ unsigned delta = x/BPU; x %= BPU;
+ for (unsigned i=0;i<n;i+=1)
+ {
+ unsigned u = get(i+delta);
+ if (x)
+ {
+ u >>= x;
+ u += get(i+delta+1) << (BPU-x);
+ }
+ set(i,u);
+ }
+}
+
+void vlong_value::add( vlong_value & x )
+{
+ unsigned carry = 0;
+ unsigned max = n; if (max<x.n) max = x.n;
+ reserve(max);
+ for (unsigned i=0;i<max+1;i+=1)
+ {
+ unsigned u = get(i);
+ u = u + carry; carry = ( u < carry );
+ unsigned ux = x.get(i);
+ u = u + ux; carry += ( u < ux );
+ set(i,u);
+ }
+}
+
+void vlong_value::subtract( vlong_value & x )
+{
+ unsigned carry = 0;
+ unsigned N = n;
+ for (unsigned i=0;i<N;i+=1)
+ {
+ unsigned ux = x.get(i);
+ ux += carry;
+ if ( ux >= carry )
+ {
+ unsigned u = get(i);
+ unsigned nu = u - ux;
+ carry = nu > u;
+ set(i,nu);
+ }
+ }
+}
+
+void vlong_value::init( unsigned x )
+{
+ clear();
+ set(0,x);
+}
+
+void vlong_value::copy( vlong_value& x )
+{
+ clear();
+ unsigned i=x.n;
+ while (i) { i -= 1; set( i, x.get(i) ); }
+}
+
+vlong_value::vlong_value()
+{
+ share = 0;
+}
+
+void vlong_value::mul( vlong_value& x, vlong_value& y )
+{
+ fast_mul( x, y, x.bits()+y.bits() );
+}
+
+void vlong_value::divide( vlong_value& x, vlong_value& y, vlong_value& rem )
+{
+ init(0);
+ rem.copy(x);
+ vlong_value m,s;
+ m.copy(y);
+ s.init(1);
+ while ( rem.cf(m) > 0 )
+ {
+ m.shl();
+ s.shl();
+ }
+ while ( rem.cf(y) >= 0 )
+ {
+ while ( rem.cf(m) < 0 )
+ {
+ m.shr();
+ s.shr();
+ }
+ rem.subtract( m );
+ add( s );
+ }
+}
+
+// Implementation of vlong
+
+void vlong::load( unsigned * a, unsigned n )
+{
+ docopy();
+ value->clear();
+ for (unsigned i=0;i<n;i+=1)
+ value->set(i,a[i]);
+}
+
+void vlong::store( unsigned * a, unsigned n ) const
+{
+ for (unsigned i=0;i<n;i+=1)
+ a[i] = value->get(i);
+}
+
+unsigned vlong::get_nunits() const
+{
+ return value->n;
+}
+
+unsigned vlong::bits() const
+{
+ return value->bits();
+}
+
+void vlong::docopy()
+{
+ if ( value->share )
+ {
+ value->share -= 1;
+ vlong_value * nv = new vlong_value;
+ nv->copy(*value);
+ value = nv;
+ }
+}
+
+int vlong::cf( const vlong x ) const
+{
+ int neg = negative && !value->is_zero();
+ //int neg2 = x.negative && !x.value->is_zero();
+
+ if ( neg == (x.negative && !x.value->is_zero()) )
+ //if ( neg == neg2)
+ return value->cf( *x.value );
+
+ else if ( neg ) return -1;
+ else return +1;
+}
+
+vlong::vlong (unsigned x)
+{
+ value = new vlong_value;
+ negative = 0;
+ value->init(x);
+}
+
+vlong::vlong ( const vlong& x ) // copy constructor
+{
+ negative = x.negative;
+ value = x.value;
+ value->share += 1;
+}
+
+vlong& vlong::operator =(const vlong& x)
+{
+ if ( value->share ) value->share -=1; else delete value;
+ value = x.value;
+ value->share += 1;
+ negative = x.negative;
+ return *this;
+}
+
+vlong::~vlong()
+{
+ if ( value->share ) value->share -=1; else delete value;
+}
+
+vlong::operator unsigned () // conversion to unsigned
+{
+ return *value;
+}
+
+vlong& vlong::operator +=(const vlong& x)
+{
+ if ( negative == x.negative )
+ {
+ docopy();
+ value->add( *x.value );
+ }
+ else if ( value->cf( *x.value ) >= 0 )
+ {
+ docopy();
+ value->subtract( *x.value );
+ }
+ else
+ {
+ vlong tmp = *this;
+ *this = x;
+ *this += tmp;
+ }
+ return *this;
+}
+
+vlong& vlong::operator -=(const vlong& x)
+{
+ if ( negative != x.negative )
+ {
+ docopy();
+ value->add( *x.value );
+ }
+ else if ( value->cf( *x.value ) >= 0 )
+ {
+ docopy();
+ value->subtract( *x.value );
+ }
+ else
+ {
+ vlong tmp = *this;
+ *this = x;
+ *this -= tmp;
+ negative = 1 - negative;
+ }
+ return *this;
+}
+
+vlong operator +( const vlong& x, const vlong& y )
+{
+ vlong result = x;
+ result += y;
+ return result;
+}
+
+vlong operator -( const vlong& x, const vlong& y )
+{
+ vlong result = x;
+ result -= y;
+ return result;
+}
+
+vlong operator *( const vlong& x, const vlong& y )
+{
+ vlong result;
+ result.value->mul( *x.value, *y.value );
+ result.negative = x.negative ^ y.negative;
+ return result;
+}
+
+vlong operator /( const vlong& x, const vlong& y )
+{
+ vlong result;
+ vlong_value rem;
+ result.value->divide( *x.value, *y.value, rem );
+ result.negative = x.negative ^ y.negative;
+ return result;
+}
+
+#if defined(__DEBUG__)
+void print_vlong( const vlong_value & v, const char *name )
+{
+ printf("%s value(%d): ", name, v.n * sizeof(unsigned int));
+ for(int i = 0; i < v.n; ++i)
+ {
+ printf("%08X", v.a[i]);
+ }
+ printf("\n");
+}
+#endif
+
+vlong operator %( const vlong& x, const vlong& y )
+{
+ vlong result;
+ vlong_value divide;
+ divide.divide( *x.value, *y.value, *result.value );
+ result.negative = x.negative; // not sure about this?
+ return result;
+}
+
+static vlong gcd( const vlong &X, const vlong &Y )
+{
+ vlong x=X, y=Y;
+ while (1)
+ {
+ if ( y == (vlong)0 ) return x;
+ x = x % y;
+ if ( x == (vlong)0 ) return y;
+ y = y % x;
+ }
+}
+
+static vlong modinv( const vlong &a, const vlong &m ) // modular inverse
+// returns i in range 1..m-1 such that i*a = 1 mod m
+// a must be in range 1..m-1
+{
+ vlong j=1,i=0,b=m,c=a,x,y;
+ while ( c != (vlong)0 )
+ {
+ x = b / c;
+ y = b - x*c;
+ b = c;
+ c = y;
+ y = j;
+ j = i - j*x;
+ i = y;
+ }
+ if ( i < (vlong)0 )
+ i += m;
+ return i;
+}
+
+class monty // class for montgomery modular exponentiation
+{
+ vlong R,R1,m,n1;
+ vlong T,k; // work registers
+ unsigned N; // bits for R
+ void mul( vlong &x, const vlong &y );
+public:
+ vlong exp( const vlong &x, const vlong &e );
+ monty( const vlong &M );
+};
+
+monty::monty( const vlong &M )
+{
+ m = M;
+ N = 0; R = 1; while ( R < M ) { R += R; N += 1; }
+ R1 = modinv( R-m, m );
+ n1 = R - modinv( m, R );
+}
+
+void monty::mul( vlong &x, const vlong &y )
+{
+ // T = x*y;
+ T.value->fast_mul( *x.value, *y.value, N*2 );
+
+ // k = ( T * n1 ) % R;
+ k.value->fast_mul( *T.value, *n1.value, N );
+
+ // x = ( T + k*m ) / R;
+ x.value->fast_mul( *k.value, *m.value, N*2 );
+ x += T;
+ x.value->shr( N );
+
+ if (x>=m) x -= m;
+}
+
+vlong monty::exp( const vlong &x, const vlong &e )
+{
+ vlong result = R-m, t = ( x * R ) % m;
+ unsigned bits = e.value->bits();
+ unsigned i = 0;
+ while (1)
+ {
+ if ( e.value->test(i) )
+ {
+ mul( result, t);
+ }
+ i += 1;
+ if ( i == bits ) break;
+ mul( t, t );
+ }
+ return ( result * R1 ) % m;
+}
+
+static vlong modexp( const vlong & x, const vlong & e, const vlong & m )
+{
+ monty me(m);
+ return me.exp( x,e );
+}
+
+// RSA.CPP -----------------------------------
+
+vlong public_key::encrypt( const vlong& plain )
+{
+#if defined(__DEBUG__)
+ if ( plain >= m ) {
+ printf("ERROR: plain too big for this key\n");
+ }
+#endif
+ return modexp( plain, e, m );
+}
+
+vlong private_key::decrypt( const vlong& cipher )
+{
+ // Calculate values for performing decryption
+ // These could be cached, but the calculation is quite fast
+ vlong d = modinv( e, (p-(vlong)1)*(q-(vlong)1) );
+ vlong u = modinv( p, q );
+ vlong dp = d % (p-(vlong)1);
+ vlong dq = d % (q-(vlong)1);
+
+ // Apply chinese remainder theorem
+ vlong a = modexp( cipher % p, dp, p );
+ vlong b = modexp( cipher % q, dq, q );
+ if ( b < a ) b += q;
+ return a + p * ( ((b-a)*u) % q );
+}
+
+void vlong_pair_2_str (char *me_str,vlong &m,vlong &e)
+{
+ const char *hex_str = "0123456789ABCDEF";
+
+ char tmp_str[MAX_CRYPT_BITS/2+1];
+
+ unsigned int x;
+ unsigned int me_len = 0;
+ unsigned int i;
+ unsigned int j;
+ vlong m1 = m;
+ vlong e1 = e;
+ vlong zero = 0;
+
+ i = 0;
+ while (m1 != zero)
+ {
+ x = m1 % (vlong) 16;
+ m1 = m1 / (vlong) 16;
+ tmp_str[i++] = hex_str[x];
+ }
+
+ for (j=0; j < i; j++)
+ me_str[me_len++] = tmp_str[i-1-j];
+
+ me_str[me_len++] = '#';
+
+ i = 0;
+ while (e1 != zero)
+ {
+ x = e1 %(vlong)16;
+ e1 = e1 / (vlong)16;
+ tmp_str[i++] = hex_str[x];
+ }
+
+ for (j=0; j < i; j++)
+ me_str[me_len++] = tmp_str[i-1-j];
+
+ me_str[me_len] = 0;
+}
+void str_2_vlong_pair (const char *me_str,vlong &m,vlong &e)
+{
+ int i;
+ int dash_pos = 0;
+ m = 0;
+ e = 0;
+
+ int me_len = (int)strlen (me_str);
+
+ for (i = me_len-1; i>0; i--)
+ if (me_str[i] == '#')
+ {
+ dash_pos = i;
+ break;
+ }
+
+ if (dash_pos == 0)
+ return;
+
+
+ for (i = 0; i<dash_pos; i++)
+ {
+ m = m * (vlong)16;
+ if (me_str[i] > '9')
+ m = m + (vlong) (me_str[i]-'A'+10);
+ else
+ m = m + (vlong) (me_str[i]-'0');
+ }
+
+ for (i = dash_pos+1; i<me_len; i++)
+ {
+ e = e * (vlong)16;
+ if (me_str[i] > '9')
+ e = e + (vlong) (me_str[i]-'A'+10);
+ else
+ e = e + (vlong) (me_str[i]-'0');
+ }
+
+
+}
+
+
+
+void private_key::MakeMeStr(char * me_str)
+{
+ vlong_pair_2_str (me_str,m,e);
+}
+
+void private_key::MakePqStr(char * me_str)
+{
+ vlong_pair_2_str (me_str,p,q);
+}
+
+void private_key::MakePq (const char *me_str)
+{
+ str_2_vlong_pair (me_str,p,q);
+ {
+ m = p*q;
+ e = 50001; // must be odd since p-1 and q-1 are even
+ while ( gcd(p-(vlong)1,e) != (vlong)1 || gcd(q-(vlong)1,e) != (vlong)1 ) e += 2;
+ }
+
+}
+
+
+void public_key::MakeMe(const char *me_str)
+{
+ str_2_vlong_pair (me_str,m,e);
+}
+
+CCryptoProviderRSA::CCryptoProviderRSA()
+{
+}
+
+CCryptoProviderRSA::~CCryptoProviderRSA()
+{
+}
+
+void inline _rmemcpy (char *dst,const char *src,size_t size)
+{
+ src += size;
+ while (size--)
+ *dst++ = *(--src);
+}
+
+void CCryptoProviderRSA::GetBlockSize(int &enbs, int &debs)
+{
+ enbs=0;
+ debs=0;
+}
+
+void CCryptoProviderRSA::EncryptPortion(const char *pt, size_t pt_size, char *ct, size_t &ct_size)
+{
+ vlong plain, cipher;
+
+ const size_t bytes_per_unit = BPU / 8;
+
+ size_t padding = (pt_size & 3) ? (4 - (pt_size & 3)) : 0;
+ char tmp[MAX_CRYPT_BITS/4];
+
+ // ensure big-endianness
+ _rmemcpy(tmp, pt, pt_size);
+ memset(tmp + pt_size, 0, padding);
+ plain.load((unsigned int*)tmp, (int)(pt_size+padding) / bytes_per_unit);
+
+ cipher = prkface.encrypt(plain);
+ ct_size = cipher.get_nunits() * bytes_per_unit;
+
+ // ensure big-endianness
+ cipher.store((unsigned int*)tmp, (int)ct_size / bytes_per_unit);
+ _rmemcpy(ct, tmp, ct_size);
+}
+
+void CCryptoProviderRSA::DecryptPortion(const char *ct, size_t ct_size, char *pt, size_t &pt_size)
+{
+ vlong plain, cipher;
+
+ const size_t bytes_per_unit = BPU / 8;
+
+ char tmp[MAX_CRYPT_BITS/4];
+
+ // ensure big-endianness
+ _rmemcpy(tmp, ct, ct_size);
+
+ cipher.load((unsigned int*)tmp, (int)ct_size / bytes_per_unit);
+ plain = prkface.decrypt(cipher);
+
+ // ensure big-endianness
+ plain.store((unsigned int*)tmp, plain.get_nunits());
+ _rmemcpy(pt, tmp, pt_size);
+}
+
+void CCryptoProviderRSA::ImportPublicKey(const char *pk)
+{
+ prkface.MakeMe(pk);
+}
+void CCryptoProviderRSA::ImportPrivateKey(const char *pk)
+{
+ prkface.MakePq(pk);
+}
+
+void CCryptoProviderRSA::ExportPublicKey(char *pk)
+{
+ prkface.MakeMeStr(pk);
+}
+
+void CCryptoProviderRSA::ExportPrivateKey(char *pk)
+{
+ prkface.MakePqStr(pk);
+}
+
+#if defined(__DEBUG__)
+void printbuf(const char * buf, int size)
+{
+ for(const char * p = buf; p < buf + size; ++p)
+ {
+ printf("%02X", *p & 0x000000ff);
+ }
+ printf("\n");
+}
+#endif
+
+void CCryptoProviderRSA::Encrypt(const char *inbuf, size_t in_size,char *outbuf, size_t &out_size)
+{
+ size_t i,cp_size;
+
+ char portbuf[MAX_CRYPT_BITS/8];
+ char cpbuf[MAX_CRYPT_BITS/4];
+ const char *inp = inbuf;
+
+ unsigned short lm;
+
+ // must ensure that any data block would be < key's modulus
+ // hence -1
+ int portion_len = (prkface.m.bits() - 1) / 8;
+ char prev_crypted[portion_len];
+ memset(&prev_crypted, 0, portion_len);
+
+ out_size = 0;
+ while(in_size)
+ {
+ size_t cur_size = in_size > portion_len ? portion_len : in_size;
+
+ for (i=0; i<cur_size; i++)
+ portbuf[i] = inp[i] ^ prev_crypted[i];
+
+ EncryptPortion(portbuf, cur_size, cpbuf, cp_size);
+
+ for (i=0; i<portion_len; i++)
+ prev_crypted[i] = i < cp_size ? cpbuf[i] : 0;
+
+ lm=cur_size;
+ memcpy (outbuf+out_size,&lm, sizeof(unsigned short)); out_size+=sizeof (unsigned short);
+ lm=(unsigned short)cp_size;
+ memcpy (outbuf+out_size,&lm, sizeof(unsigned short)); out_size+=sizeof (unsigned short);
+ memcpy (outbuf+out_size,cpbuf, cp_size); out_size+=cp_size;
+ inp+=cur_size;
+ in_size-=cur_size;
+ }
+
+ return;
+}
+
+void CCryptoProviderRSA::Decrypt(const char *inbuf, size_t in_size,char *outbuf, size_t &out_size)
+{
+ size_t i, cp_size,pt_size;
+
+ char portbuf[MAX_CRYPT_BITS/8];
+ char cpbuf[MAX_CRYPT_BITS/4];
+
+ unsigned short lmi, lmo;
+
+ // must ensure that any data block would be < key's modulus
+ // hence -1
+ int portion_len = (prkface.m.bits() - 1) / 8;
+ char prev_crypted[portion_len];
+ memset(&prev_crypted, 0, portion_len);
+
+ const char *inp=inbuf;
+ out_size = 0;
+
+ while(in_size)
+ {
+ memcpy (&lmi,inp,sizeof (unsigned short)); inp += sizeof(unsigned short); in_size -= sizeof(unsigned short);
+ memcpy (&lmo,inp,sizeof (unsigned short)); inp += sizeof(unsigned short); in_size -= sizeof(unsigned short);
+
+ if (lmo>in_size)
+ break;
+
+ memcpy (cpbuf,inp,lmo);
+ cp_size = lmo;
+ pt_size = lmi;
+
+ DecryptPortion(cpbuf, cp_size, portbuf, pt_size);
+
+ if (lmi>pt_size)
+ lmi=(unsigned short)pt_size;
+
+ for (i=0; i<lmi; i++)
+ portbuf[i] ^= prev_crypted[i];
+
+ for (i=0; i<portion_len; i++)
+ prev_crypted[i] = i < cp_size ? cpbuf[i] : 0;
+
+ memcpy (outbuf+out_size,portbuf,lmi);
+ out_size += lmi;
+
+ inp+=lmo;
+ in_size-=lmo;
+ }
+ return;
+}