v0.2.2 release
[yandexfotkisp] / src / CP_RSA.cpp
1 /*
2  * Based on code parts from pegwit program written by George Barwood.
3  * This code is in the public domain; do with it what you wish.
4  *
5  **/
6 #if defined(__DEBUG__)
7 #include <cstdio>
8 #endif
9
10 #include "string.h"
11 #include "stdlib.h"
12 #include "CP_RSA.h"
13
14
15 static vlong modexp( const vlong & x, const vlong & e, const vlong & m ); // m must be odd
16 static vlong gcd( const vlong &X, const vlong &Y ); // greatest common denominator
17 static vlong modinv( const vlong &a, const vlong &m ); // modular inverse
18
19 // VLONG.CPP -----------------------------------
20
21 class flex_unit // Provides storage allocation and index checking
22 {
23 public:
24
25         unsigned * a; // array of units
26         unsigned z; // units allocated
27
28         unsigned n; // used units (read-only)
29         flex_unit();
30         ~flex_unit();
31         void clear(); // set n to zero
32         unsigned get( unsigned i ) const;               // get ith unsigned
33         void set( unsigned i, unsigned x );     // set ith unsigned
34         void reserve( unsigned x );                     // storage hint
35
36         // Time critical routine
37         void fast_mul( flex_unit &x, flex_unit &y, unsigned n );
38 };
39
40 class vlong_value : public flex_unit
41 {
42         public:
43         unsigned share; // share count, used by vlong to delay physical copying
44         int is_zero() const;
45         int test( unsigned i ) const;
46         unsigned bits() const;
47         int cf( vlong_value& x ) const;
48         void shl();
49         void shr();
50         void shr( unsigned n );
51         void add( vlong_value& x );
52         void subtract( vlong_value& x );
53         void init( unsigned x );
54         void copy( vlong_value& x );
55         operator unsigned(); // Unsafe conversion to unsigned
56         vlong_value();
57         void mul( vlong_value& x, vlong_value& y );
58         void divide( vlong_value& x, vlong_value& y, vlong_value& rem );
59 };
60
61 unsigned flex_unit::get( unsigned i ) const
62 {
63         if ( i >= n ) return 0;
64         return a[i];
65 }
66
67 void flex_unit::clear()
68 {
69         n = 0;
70 }
71
72 flex_unit::flex_unit()
73 {
74         z = 0;
75         a = 0;
76         n = 0;
77 }
78
79 flex_unit::~flex_unit()
80 {
81         unsigned i=z;
82         while (i) { i-=1; a[i] = 0; } // burn
83         delete [] a;
84 }
85
86 void flex_unit::reserve( unsigned x )
87 {
88         if (x > z)
89         {
90                 unsigned * na = new unsigned[x];
91                 for (unsigned i=0;i<n;i+=1) na[i] = a[i];
92                 delete [] a;
93                 a = na;
94                 z = x;
95         }
96 }
97
98 void flex_unit::set( unsigned i, unsigned x )
99 {
100         if ( i < n )
101         {
102                 a[i] = x;
103                 if (x==0) while (n && a[n-1]==0) n-=1; // normalise
104         }
105         else if ( x )
106         {
107                 reserve(i+1);
108                 for (unsigned j=n;j<i;j+=1) a[j] = 0;
109                 a[i] = x;
110                 n = i+1;
111         }
112 }
113
114 // Macros for doing double precision multiply
115 #define BPU ( 8*sizeof(unsigned) )               // Number of bits in an unsigned
116 #define lo(x) ( (x) & ((1<<(BPU/2))-1) ) // lower half of unsigned
117 #define hi(x) ( (x) >> (BPU/2) )                 // upper half
118 #define lh(x) ( (x) << (BPU/2) )                 // make upper half
119
120 void flex_unit::fast_mul( flex_unit &x, flex_unit &y, unsigned keep )
121 {
122         // *this = (x*y) % (2**keep)
123         unsigned i,j,limit = (keep+BPU-1)/BPU; // size of result in words
124         reserve(limit); for (i=0; i<limit; i+=1) a[i] = 0;
125         unsigned min = x.n; if (min>limit) min = limit;
126         for (i=0; i<min; i+=1)
127         {
128                 unsigned m = x.a[i];
129                 unsigned c = 0; // carry
130                 unsigned min = i+y.n; if (min>limit) min = limit;
131                 for ( j=i; j<min; j+=1 )
132                 {
133                         // This is the critical loop
134                         // Machine dependent code could help here
135                         // c:a[j] = a[j] + c + m*y.a[j-i];
136                         unsigned w, v = a[j], p = y.a[j-i];
137                         v += c; c = ( v < c );
138                         w = lo(p)*lo(m); v += w; c += ( v < w );
139                         w = lo(p)*hi(m); c += hi(w); w = lh(w); v += w; c += ( v < w );
140                         w = hi(p)*lo(m); c += hi(w); w = lh(w); v += w; c += ( v < w );
141                         c += hi(p) * hi(m);
142                         a[j] = v;
143                 }
144                 while ( c && j<limit )
145                 {
146                         a[j] += c;
147                         c = a[j] < c;
148                         j += 1;
149                 }
150         }
151
152         // eliminate unwanted bits
153         keep %= BPU; if (keep) a[limit-1] &= (1<<keep)-1;
154
155         // calculate n
156         while (limit && a[limit-1]==0) limit-=1;
157         n = limit;
158 };
159
160 vlong_value::operator unsigned()
161 {
162         return get(0);
163 }
164
165 int vlong_value::is_zero() const
166 {
167         return n==0;
168 }
169
170 int vlong_value::test( unsigned i ) const
171 { return ( get(i/BPU) & (1<<(i%BPU)) ) != 0; }
172
173 unsigned vlong_value::bits() const
174 {
175         unsigned x = n*BPU;
176         while (x && test(x-1)==0) x -= 1;
177         return x;
178 }
179
180 int vlong_value::cf( vlong_value& x ) const
181 {
182         if ( n > x.n ) return +1;
183         if ( n < x.n ) return -1;
184         unsigned i = n;
185         while (i)
186         {
187                 i -= 1;
188                 if ( get(i) > x.get(i) ) return +1;
189                 if ( get(i) < x.get(i) ) return -1;
190         }
191         return 0;
192 }
193
194 void vlong_value::shl()
195 {
196         unsigned carry = 0;
197         unsigned N = n; // necessary, since n can change
198         for (unsigned i=0;i<=N;i+=1)
199         {
200                 unsigned u = get(i);
201                 set(i,(u<<1)+carry);
202                 carry = u>>(BPU-1);
203         }
204 }
205
206 void vlong_value::shr()
207 {
208         unsigned carry = 0;
209         unsigned i=n;
210         while (i)
211         {
212                 i -= 1;
213                 unsigned u = get(i);
214                 set(i,(u>>1)+carry);
215                 carry = u<<(BPU-1);
216         }
217 }
218
219 void vlong_value::shr( unsigned x )
220 {
221         unsigned delta = x/BPU; x %= BPU;
222         for (unsigned i=0;i<n;i+=1)
223         {
224                 unsigned u = get(i+delta);
225                 if (x)
226                 {
227                         u >>= x;
228                         u += get(i+delta+1) << (BPU-x);
229                 }
230                 set(i,u);
231         }
232 }
233
234 void vlong_value::add( vlong_value & x )
235 {
236         unsigned carry = 0;
237         unsigned max = n; if (max<x.n) max = x.n;
238         reserve(max);
239         for (unsigned i=0;i<max+1;i+=1)
240         {
241                 unsigned u = get(i);
242                 u = u + carry; carry = ( u < carry );
243                 unsigned ux = x.get(i);
244                 u = u + ux; carry += ( u < ux );
245                 set(i,u);
246         }
247 }
248
249 void vlong_value::subtract( vlong_value & x )
250 {
251         unsigned carry = 0;
252         unsigned N = n;
253         for (unsigned i=0;i<N;i+=1)
254         {
255                 unsigned ux = x.get(i);
256                 ux += carry;
257                 if ( ux >= carry )
258                 {
259                         unsigned u = get(i);
260                         unsigned nu = u - ux;
261                         carry = nu > u;
262                         set(i,nu);
263                 }
264         }
265 }
266
267 void vlong_value::init( unsigned x )
268 {
269         clear();
270         set(0,x);
271 }
272
273 void vlong_value::copy( vlong_value& x )
274 {
275         clear();
276         unsigned i=x.n;
277         while (i) { i -= 1; set( i, x.get(i) ); }
278 }
279
280 vlong_value::vlong_value()
281 {
282         share = 0;
283 }
284
285 void vlong_value::mul( vlong_value& x, vlong_value& y )
286 {
287         fast_mul( x, y, x.bits()+y.bits() );
288 }
289
290 void vlong_value::divide( vlong_value& x, vlong_value& y, vlong_value& rem )
291 {
292         init(0);
293         rem.copy(x);
294         vlong_value m,s;
295         m.copy(y);
296         s.init(1);
297         while ( rem.cf(m) > 0 )
298         {
299                 m.shl();
300                 s.shl();
301         }
302         while ( rem.cf(y) >= 0 )
303         {
304                 while ( rem.cf(m) < 0 )
305                 {
306                         m.shr();
307                         s.shr();
308                 }
309                 rem.subtract( m );
310                 add( s );
311         }
312 }
313
314 // Implementation of vlong
315
316 void vlong::load( unsigned * a, unsigned n )
317 {
318         docopy();
319         value->clear();
320         for (unsigned i=0;i<n;i+=1)
321                 value->set(i,a[i]);
322 }
323
324 void vlong::store( unsigned * a, unsigned n ) const
325 {
326         for (unsigned i=0;i<n;i+=1)
327                 a[i] = value->get(i);
328 }
329
330 unsigned vlong::get_nunits() const
331 {
332         return value->n;
333 }
334
335 unsigned vlong::bits() const
336 {
337         return value->bits();
338 }
339
340 void vlong::docopy()
341 {
342         if ( value->share )
343         {
344                 value->share -= 1;
345                 vlong_value * nv = new vlong_value;
346                 nv->copy(*value);
347                 value = nv;
348         }
349 }
350
351 int vlong::cf( const vlong x ) const
352 {
353         int neg = negative && !value->is_zero();
354         //int neg2 = x.negative && !x.value->is_zero();
355
356         if ( neg == (x.negative && !x.value->is_zero()) )
357         //if ( neg == neg2)
358                 return value->cf( *x.value );
359
360         else if ( neg ) return -1;
361         else return +1;
362 }
363
364 vlong::vlong (unsigned x)
365 {
366         value = new vlong_value;
367         negative = 0;
368         value->init(x);
369 }
370
371 vlong::vlong ( const vlong& x ) // copy constructor
372 {
373         negative = x.negative;
374         value = x.value;
375         value->share += 1;
376 }
377
378 vlong& vlong::operator =(const vlong& x)
379 {
380         if ( value->share ) value->share -=1; else delete value;
381         value = x.value;
382         value->share += 1;
383         negative = x.negative;
384         return *this;
385 }
386
387 vlong::~vlong()
388 {
389         if ( value->share ) value->share -=1; else delete value;
390 }
391
392 vlong::operator unsigned () // conversion to unsigned
393 {
394         return *value;
395 }
396
397 vlong& vlong::operator +=(const vlong& x)
398 {
399         if ( negative == x.negative )
400         {
401                 docopy();
402                 value->add( *x.value );
403         }
404         else if ( value->cf( *x.value ) >= 0 )
405         {
406                 docopy();
407                 value->subtract( *x.value );
408         }
409         else
410         {
411                 vlong tmp = *this;
412                 *this = x;
413                 *this += tmp;
414         }
415         return *this;
416 }
417
418 vlong& vlong::operator -=(const vlong& x)
419 {
420         if ( negative != x.negative )
421         {
422                 docopy();
423                 value->add( *x.value );
424         }
425         else if ( value->cf( *x.value ) >= 0 )
426         {
427                 docopy();
428                 value->subtract( *x.value );
429         }
430         else
431         {
432                 vlong tmp = *this;
433                 *this = x;
434                 *this -= tmp;
435                 negative = 1 - negative;
436         }
437         return *this;
438 }
439
440 vlong operator +( const vlong& x, const vlong& y )
441 {
442         vlong result = x;
443         result += y;
444         return result;
445 }
446
447 vlong operator -( const vlong& x, const vlong& y )
448 {
449         vlong result = x;
450         result -= y;
451         return result;
452 }
453
454 vlong operator *( const vlong& x, const vlong& y )
455 {
456         vlong result;
457         result.value->mul( *x.value, *y.value );
458         result.negative = x.negative ^ y.negative;
459         return result;
460 }
461
462 vlong operator /( const vlong& x, const vlong& y )
463 {
464         vlong result;
465         vlong_value rem;
466         result.value->divide( *x.value, *y.value, rem );
467         result.negative = x.negative ^ y.negative;
468         return result;
469 }
470
471 #if defined(__DEBUG__)
472 void print_vlong( const vlong_value & v, const char *name )
473 {
474         printf("%s value(%d): ", name, v.n * sizeof(unsigned int));
475         for(int i = 0; i < v.n; ++i)
476         {
477                 printf("%08X", v.a[i]);
478         }
479         printf("\n");
480 }
481 #endif
482
483 vlong operator %( const vlong& x, const vlong& y )
484 {
485         vlong result;
486         vlong_value divide;
487         divide.divide( *x.value, *y.value, *result.value );
488         result.negative = x.negative; // not sure about this?
489         return result;
490 }
491
492 static vlong gcd( const vlong &X, const vlong &Y )
493 {
494         vlong x=X, y=Y;
495         while (1)
496         {
497                 if ( y == (vlong)0 ) return x;
498                 x = x % y;
499                 if ( x == (vlong)0 ) return y;
500                 y = y % x;
501         }
502 }
503
504 static vlong modinv( const vlong &a, const vlong &m ) // modular inverse
505 // returns i in range 1..m-1 such that i*a = 1 mod m
506 // a must be in range 1..m-1
507 {
508         vlong j=1,i=0,b=m,c=a,x,y;
509         while ( c != (vlong)0 )
510         {
511                 x = b / c;
512                 y = b - x*c;
513                 b = c;
514                 c = y;
515                 y = j;
516                 j = i - j*x;
517                 i = y;
518         }
519         if ( i < (vlong)0 )
520                 i += m;
521         return i;
522 }
523
524 class monty // class for montgomery modular exponentiation
525 {
526         vlong R,R1,m,n1;
527         vlong T,k;   // work registers
528         unsigned N;  // bits for R
529         void mul( vlong &x, const vlong &y );
530 public:
531         vlong exp( const vlong &x, const vlong &e );
532         monty( const vlong &M );
533 };
534
535 monty::monty( const vlong &M )
536 {
537         m = M;
538         N = 0; R = 1; while ( R < M ) { R += R; N += 1; }
539         R1 = modinv( R-m, m );
540         n1 = R - modinv( m, R );
541 }
542
543 void monty::mul( vlong &x, const vlong &y )
544 {
545         // T = x*y;
546         T.value->fast_mul( *x.value, *y.value, N*2 );
547
548         // k = ( T * n1 ) % R;
549         k.value->fast_mul( *T.value, *n1.value, N );
550
551         // x = ( T + k*m ) / R;
552         x.value->fast_mul( *k.value, *m.value, N*2 );
553         x += T;
554         x.value->shr( N );
555
556         if (x>=m) x -= m;
557 }
558
559 vlong monty::exp( const vlong &x, const vlong &e )
560 {
561         vlong result = R-m, t = ( x * R ) % m;
562         unsigned bits = e.value->bits();
563         unsigned i = 0;
564         while (1)
565         {
566                 if ( e.value->test(i) )
567                 {
568                         mul( result, t);
569                 }
570                 i += 1;
571                 if ( i == bits ) break;
572                 mul( t, t );
573         }
574         return ( result * R1 ) % m;
575 }
576
577 static vlong modexp( const vlong & x, const vlong & e, const vlong & m )
578 {
579         monty me(m);
580         return me.exp( x,e );
581 }
582
583 // RSA.CPP -----------------------------------
584
585 vlong public_key::encrypt( const vlong& plain )
586 {
587 #if defined(__DEBUG__)
588         if ( plain >= m ) {
589                 printf("ERROR: plain too big for this key\n");
590         }
591 #endif
592         return modexp( plain, e, m );
593 }
594
595 vlong private_key::decrypt( const vlong& cipher )
596 {
597         // Calculate values for performing decryption
598         // These could be cached, but the calculation is quite fast
599         vlong d = modinv( e, (p-(vlong)1)*(q-(vlong)1) );
600         vlong u = modinv( p, q );
601         vlong dp = d % (p-(vlong)1);
602         vlong dq = d % (q-(vlong)1);
603
604         // Apply chinese remainder theorem
605         vlong a = modexp( cipher % p, dp, p );
606         vlong b = modexp( cipher % q, dq, q );
607         if ( b < a ) b += q;
608         return a + p * ( ((b-a)*u) % q );
609 }
610
611 void vlong_pair_2_str (char *me_str,vlong &m,vlong &e)
612 {
613         const char *hex_str = "0123456789ABCDEF";
614
615         char tmp_str[MAX_CRYPT_BITS/2+1];
616
617         unsigned int x;
618         unsigned int me_len = 0;
619         unsigned int i;
620         unsigned int j;
621         vlong m1 = m;
622         vlong e1 = e;
623         vlong zero = 0;
624
625         i = 0;
626         while (m1 != zero)
627         {
628                 x = m1 % (vlong) 16;
629                 m1 = m1 / (vlong) 16;
630                 tmp_str[i++] = hex_str[x];
631         }
632
633         for (j=0; j < i; j++)
634                 me_str[me_len++] = tmp_str[i-1-j];
635
636         me_str[me_len++] = '#';
637
638         i = 0;
639         while (e1 != zero)
640         {
641                 x = e1 %(vlong)16;
642                 e1 = e1 / (vlong)16;
643                 tmp_str[i++] = hex_str[x];
644         }
645
646         for (j=0; j < i; j++)
647                 me_str[me_len++] = tmp_str[i-1-j];
648
649         me_str[me_len] = 0;
650 }
651 void str_2_vlong_pair (const char *me_str,vlong &m,vlong &e)
652 {
653         int i;
654         int dash_pos = 0;
655         m = 0;
656         e = 0;
657
658         int me_len = (int)strlen (me_str);
659
660         for (i = me_len-1; i>0; i--)
661                 if (me_str[i] == '#')
662                 {
663                         dash_pos = i;
664                         break;
665                 }
666
667         if (dash_pos == 0)
668                 return;
669
670
671         for (i = 0; i<dash_pos; i++)
672         {
673                 m = m * (vlong)16;
674                 if (me_str[i] > '9')
675                         m = m + (vlong) (me_str[i]-'A'+10);
676                 else
677                         m = m + (vlong) (me_str[i]-'0');
678         }
679
680         for (i = dash_pos+1; i<me_len; i++)
681         {
682                 e = e * (vlong)16;
683                 if (me_str[i] > '9')
684                         e = e + (vlong) (me_str[i]-'A'+10);
685                 else
686                         e = e + (vlong) (me_str[i]-'0');
687         }
688
689
690 }
691
692
693
694 void private_key::MakeMeStr(char * me_str)
695 {
696         vlong_pair_2_str (me_str,m,e);
697 }
698
699 void private_key::MakePqStr(char * me_str)
700 {
701         vlong_pair_2_str (me_str,p,q);
702 }
703
704 void private_key::MakePq (const char *me_str)
705 {
706         str_2_vlong_pair (me_str,p,q);
707         {
708         m = p*q;
709         e = 50001; // must be odd since p-1 and q-1 are even
710         while ( gcd(p-(vlong)1,e) != (vlong)1 || gcd(q-(vlong)1,e) != (vlong)1 ) e += 2;
711         }
712
713 }
714
715
716 void public_key::MakeMe(const char *me_str)
717 {
718         str_2_vlong_pair (me_str,m,e);
719 }
720
721 CCryptoProviderRSA::CCryptoProviderRSA()
722 {
723 }
724
725 CCryptoProviderRSA::~CCryptoProviderRSA()
726 {
727 }
728
729 void inline _rmemcpy (char *dst,const char *src,size_t size)
730 {
731         src += size;
732         while (size--)
733                 *dst++ = *(--src);
734 }
735
736 void CCryptoProviderRSA::GetBlockSize(int &enbs, int &debs)
737 {
738         enbs=0;
739         debs=0;
740 }
741
742 void CCryptoProviderRSA::EncryptPortion(const char *pt, size_t pt_size, char *ct, size_t &ct_size)
743 {
744         vlong plain, cipher;
745
746         const size_t bytes_per_unit = BPU / 8;
747
748         size_t padding = (pt_size & 3) ? (4 - (pt_size & 3)) : 0;
749         char tmp[MAX_CRYPT_BITS/4];
750
751         // ensure big-endianness
752         _rmemcpy(tmp, pt, pt_size);
753         memset(tmp + pt_size, 0, padding);
754         plain.load((unsigned int*)tmp, (int)(pt_size+padding) / bytes_per_unit);
755
756         cipher = prkface.encrypt(plain);
757         ct_size = cipher.get_nunits() * bytes_per_unit;
758
759         // ensure big-endianness
760         cipher.store((unsigned int*)tmp, (int)ct_size / bytes_per_unit);
761         _rmemcpy(ct, tmp, ct_size);
762 }
763
764 void CCryptoProviderRSA::DecryptPortion(const char *ct, size_t ct_size, char *pt, size_t &pt_size)
765 {
766         vlong plain, cipher;
767
768         const size_t bytes_per_unit = BPU / 8;
769
770         char tmp[MAX_CRYPT_BITS/4];
771
772         // ensure big-endianness
773         _rmemcpy(tmp, ct, ct_size);
774
775         cipher.load((unsigned int*)tmp, (int)ct_size / bytes_per_unit);
776         plain = prkface.decrypt(cipher);
777
778         // ensure big-endianness
779         plain.store((unsigned int*)tmp, plain.get_nunits());
780         _rmemcpy(pt, tmp, pt_size);
781 }
782
783 void CCryptoProviderRSA::ImportPublicKey(const char *pk)
784 {
785         prkface.MakeMe(pk);
786 }
787 void CCryptoProviderRSA::ImportPrivateKey(const char *pk)
788 {
789         prkface.MakePq(pk);
790 }
791
792 void CCryptoProviderRSA::ExportPublicKey(char *pk)
793 {
794         prkface.MakeMeStr(pk);
795 }
796
797 void CCryptoProviderRSA::ExportPrivateKey(char *pk)
798 {
799         prkface.MakePqStr(pk);
800 }
801
802 #if defined(__DEBUG__)
803 void printbuf(const char * buf, int size)
804 {
805         for(const char * p = buf; p < buf + size; ++p)
806         {
807                 printf("%02X", *p & 0x000000ff);
808         }
809         printf("\n");
810 }
811 #endif
812
813 void CCryptoProviderRSA::Encrypt(const char *inbuf, size_t in_size,char *outbuf, size_t &out_size)
814 {
815         size_t i,cp_size;
816
817         char portbuf[MAX_CRYPT_BITS/8];
818         char cpbuf[MAX_CRYPT_BITS/4];
819         const char *inp = inbuf;
820
821         unsigned short lm;
822
823         // must ensure that any data block would be < key's modulus
824         // hence -1
825         int portion_len = (prkface.m.bits() - 1)  / 8;
826         char prev_crypted[portion_len];
827         memset(&prev_crypted, 0, portion_len);
828
829         out_size = 0;
830         while(in_size)
831         {
832                 size_t cur_size = in_size > portion_len ? portion_len : in_size;
833
834                 for (i=0; i<cur_size; i++)
835                         portbuf[i] = inp[i] ^ prev_crypted[i];
836
837                 EncryptPortion(portbuf, cur_size, cpbuf, cp_size);
838
839                 for (i=0; i<portion_len; i++)
840                         prev_crypted[i] = i < cp_size ? cpbuf[i] : 0;
841
842                 lm=cur_size;
843                 memcpy (outbuf+out_size,&lm, sizeof(unsigned short)); out_size+=sizeof (unsigned short);
844                 lm=(unsigned short)cp_size;
845                 memcpy (outbuf+out_size,&lm, sizeof(unsigned short)); out_size+=sizeof (unsigned short);
846                 memcpy (outbuf+out_size,cpbuf, cp_size); out_size+=cp_size;
847                 inp+=cur_size;
848                 in_size-=cur_size;
849         }
850
851         return;
852 }
853
854 void CCryptoProviderRSA::Decrypt(const char *inbuf, size_t in_size,char *outbuf, size_t &out_size)
855 {
856         size_t i, cp_size,pt_size;
857
858         char portbuf[MAX_CRYPT_BITS/8];
859         char cpbuf[MAX_CRYPT_BITS/4];
860
861         unsigned short lmi, lmo;
862
863         // must ensure that any data block would be < key's modulus
864         // hence -1
865         int portion_len = (prkface.m.bits() - 1)  / 8;
866         char prev_crypted[portion_len];
867         memset(&prev_crypted, 0, portion_len);
868
869         const char *inp=inbuf;
870         out_size = 0;
871
872         while(in_size)
873         {
874                 memcpy (&lmi,inp,sizeof (unsigned short)); inp += sizeof(unsigned short); in_size -= sizeof(unsigned short);
875                 memcpy (&lmo,inp,sizeof (unsigned short)); inp += sizeof(unsigned short); in_size -= sizeof(unsigned short);
876
877                 if (lmo>in_size)
878                         break;
879
880                 memcpy (cpbuf,inp,lmo);
881                 cp_size = lmo;
882                 pt_size = lmi;
883
884                 DecryptPortion(cpbuf, cp_size, portbuf, pt_size);
885
886                 if (lmi>pt_size)
887                         lmi=(unsigned short)pt_size;
888
889                 for (i=0; i<lmi; i++)
890                         portbuf[i] ^= prev_crypted[i];
891
892                 for (i=0; i<portion_len; i++)
893                         prev_crypted[i] = i < cp_size ? cpbuf[i] : 0;
894
895                 memcpy (outbuf+out_size,portbuf,lmi);
896                 out_size += lmi;
897
898                 inp+=lmo;
899                 in_size-=lmo;
900         }
901         return;
902 }