1 /* ============================================================
2  *
3  * This file is a part of KDE project
4  *
5  *
6  * Date        : 2010-11-14
7  * Description : Yandex authentication module
8  *
9  * This is an Yandex implementation of RSA algorithm.
10  * It differs from the standard RSA and incompatible with it.
11  *
12  * Based on code parts from pegwit program written by George Barwood.
13  * This code is in the public domain; do with it what you wish.
14  *
15  * See links for more details:
16  *  Author homepage
17  *    http://www.george-barwood.pwp.blueyonder.co.uk/hp/
18  *
19  *  Getting token for Yandex.Fotki web service
20  *    http://api.yandex.ru/fotki/doc/overview/authorization-token.xml
21  *
22  *  Yandex published source code
23  *    http://download.yandex.ru/api-fotki/c-yamrsa.tar.gz
24  *
25  *  Yandex company web site
26  *    http://company.yandex.com/
27  *
28  * Included by Roman Tsisyk <roman at tsisyk dot com>
29  * All unneeded parts was commented out and can be removed
30  *
31  * ============================================================ */
32 
33 #include "yandexrsa.h"
34 
35 // C++ includes
36 
37 #include <cstdlib> // std::size_t
38 #include <cstring>
39 
40 namespace YandexAuth
41 {
42 
43 static vlong modexp( const vlong& x, const vlong& e, const vlong& m );    // m must be odd
44 //static vlong gcd( const vlong &X, const vlong &Y ); // greatest common denominator
45 static vlong modinv( const vlong& a, const vlong& m ); // modular inverse
46 
47 // VLONG.CPP -----------------------------------
48 
49 class flex_unit // Provides storage allocation and index checking
50 {
51 public:
52 
53     unsigned* a;  // array of units
54     unsigned z; // units allocated
55 
56     unsigned n; // used units (read-only)
57     flex_unit();
58     ~flex_unit();
59     void clear(); // set n to zero
60     unsigned get( unsigned i ) const;       // get ith unsigned
61     void set( unsigned i, unsigned x ); // set ith unsigned
62     void reserve( unsigned x );         // storage hint
63 
64     // Time critical routine
65     void fast_mul( flex_unit& x, flex_unit& y, unsigned n );
66 };
67 
68 class vlong_value : public flex_unit
69 {
70 public:
71     unsigned share; // share count, used by vlong to delay physical copying
72     int is_zero() const;
73     int test( unsigned i ) const;
74     unsigned bits() const;
75     int cf( vlong_value& x ) const;
76     void shl();
77     void shr();
78     void shr( unsigned n );
79     void add( vlong_value& x );
80     void subtract( vlong_value& x );
81     void init( unsigned x );
82     void copy( vlong_value& x );
83     operator unsigned(); // Unsafe conversion to unsigned
84     vlong_value();
85     void mul( vlong_value& x, vlong_value& y );
86     void divide( vlong_value& x, vlong_value& y, vlong_value& rem );
87 };
88 
get(unsigned i) const89 unsigned flex_unit::get( unsigned i ) const
90 {
91     if ( i >= n )
92     {
93         return 0;
94     }
95 
96     return a[i];
97 }
98 
clear()99 void flex_unit::clear()
100 {
101     n = 0;
102 }
103 
flex_unit()104 flex_unit::flex_unit()
105 {
106     z = 0;
107     a = nullptr;
108     n = 0;
109 }
110 
~flex_unit()111 flex_unit::~flex_unit()
112 {
113     unsigned i=z;
114 
115     while (i)
116     {
117         i-=1;    // burn
118         a[i] = 0;
119     }
120 
121     delete [] a;
122 }
123 
reserve(unsigned x)124 void flex_unit::reserve( unsigned x )
125 {
126     if (x > z)
127     {
128         unsigned* na = new unsigned[x];
129 
130         for (unsigned i=0; i<n; i+=1)
131         {
132             na[i] = a[i];
133         }
134 
135         delete [] a;
136         a = na;
137         z = x;
138     }
139 }
140 
set(unsigned i,unsigned x)141 void flex_unit::set( unsigned i, unsigned x )
142 {
143     if ( i < n )
144     {
145         a[i] = x;
146 
147         if (x==0) while (n && a[n-1]==0)
148             {
149                 n-=1;    // normalise
150             }
151     }
152     else if ( x )
153     {
154         reserve(i+1);
155 
156         for (unsigned j=n; j<i; j+=1)
157         {
158             a[j] = 0;
159         }
160 
161         a[i] = x;
162         n = i+1;
163     }
164 }
165 
166 // Macros for doing double precision multiply
167 #define BPU ( 8*sizeof(unsigned) )       // Number of bits in an unsigned
168 #define lo(x) ( (x) & ((1<<(BPU/2))-1) ) // lower half of unsigned
169 #define hi(x) ( (x) >> (BPU/2) )         // upper half
170 #define lh(x) ( (x) << (BPU/2) )         // make upper half
171 
fast_mul(flex_unit & x,flex_unit & y,unsigned keep)172 void flex_unit::fast_mul( flex_unit& x, flex_unit& y, unsigned keep )
173 {
174     // *this = (x*y) % (2**keep)
175     unsigned i,j,limit = (keep+BPU-1)/BPU; // size of result in words
176     reserve(limit);
177 
178     for (i=0; i<limit; i+=1)
179     {
180         a[i] = 0;
181     }
182 
183     unsigned min = x.n;
184 
185     if (min>limit)
186     {
187         min = limit;
188     }
189 
190     for (i=0; i<min; i+=1)
191     {
192         unsigned m = x.a[i];
193         unsigned c = 0; // carry
194         unsigned min = i+y.n;
195 
196         if (min>limit)
197         {
198             min = limit;
199         }
200 
201         for ( j=i; j<min; j+=1 )
202         {
203             // This is the critical loop
204             // Machine dependent code could help here
205             // c:a[j] = a[j] + c + m*y.a[j-i];
206             unsigned w, v = a[j], p = y.a[j-i];
207             v += c;
208             c = ( v < c );
209             w = lo(p)*lo(m);
210             v += w;
211             c += ( v < w );
212             w = lo(p)*hi(m);
213             c += hi(w);
214             w = lh(w);
215             v += w;
216             c += ( v < w );
217             w = hi(p)*lo(m);
218             c += hi(w);
219             w = lh(w);
220             v += w;
221             c += ( v < w );
222             c += hi(p) * hi(m);
223             a[j] = v;
224         }
225 
226         while ( c && j<limit )
227         {
228             a[j] += c;
229             c = a[j] < c;
230             j += 1;
231         }
232     }
233 
234     // eliminate unwanted bits
235     keep %= BPU;
236 
237     if (keep)
238     {
239         a[limit-1] &= (1<<keep)-1;
240     }
241 
242     // calculate n
243     while (limit && a[limit-1]==0)
244     {
245         limit-=1;
246     }
247 
248     n = limit;
249 }
250 
operator unsigned()251 vlong_value::operator unsigned()
252 {
253     return get(0);
254 }
255 
is_zero() const256 int vlong_value::is_zero() const
257 {
258     return n==0;
259 }
260 
test(unsigned i) const261 int vlong_value::test( unsigned i ) const
262 {
263     return ( get(i/BPU) & (1<<(i%BPU)) ) != 0;
264 }
265 
bits() const266 unsigned vlong_value::bits() const
267 {
268     unsigned x = n*BPU;
269 
270     while (x && test(x-1)==0)
271     {
272         x -= 1;
273     }
274 
275     return x;
276 }
277 
cf(vlong_value & x) const278 int vlong_value::cf( vlong_value& x ) const
279 {
280     if ( n > x.n )
281     {
282         return +1;
283     }
284 
285     if ( n < x.n )
286     {
287         return -1;
288     }
289 
290     unsigned i = n;
291 
292     while (i)
293     {
294         i -= 1;
295 
296         if ( get(i) > x.get(i) )
297         {
298             return +1;
299         }
300 
301         if ( get(i) < x.get(i) )
302         {
303             return -1;
304         }
305     }
306 
307     return 0;
308 }
309 
shl()310 void vlong_value::shl()
311 {
312     unsigned carry = 0;
313     unsigned N = n; // necessary, since n can change
314 
315     for (unsigned i=0; i<=N; i+=1)
316     {
317         unsigned u = get(i);
318         set(i,(u<<1)+carry);
319         carry = u>>(BPU-1);
320     }
321 }
322 
shr()323 void vlong_value::shr()
324 {
325     unsigned carry = 0;
326     unsigned i=n;
327 
328     while (i)
329     {
330         i -= 1;
331         unsigned u = get(i);
332         set(i,(u>>1)+carry);
333         carry = u<<(BPU-1);
334     }
335 }
336 
shr(unsigned x)337 void vlong_value::shr( unsigned x )
338 {
339     unsigned delta = x/BPU;
340     x %= BPU;
341 
342     for (unsigned i=0; i<n; i+=1)
343     {
344         unsigned u = get(i+delta);
345 
346         if (x)
347         {
348             u >>= x;
349             u += get(i+delta+1) << (BPU-x);
350         }
351 
352         set(i,u);
353     }
354 }
355 
add(vlong_value & x)356 void vlong_value::add( vlong_value& x )
357 {
358     unsigned carry = 0;
359     unsigned max = n;
360 
361     if (max<x.n)
362     {
363         max = x.n;
364     }
365 
366     reserve(max);
367 
368     for (unsigned i=0; i<max+1; i+=1)
369     {
370         unsigned u = get(i);
371         u = u + carry;
372         carry = ( u < carry );
373         unsigned ux = x.get(i);
374         u = u + ux;
375         carry += ( u < ux );
376         set(i,u);
377     }
378 }
379 
subtract(vlong_value & x)380 void vlong_value::subtract( vlong_value& x )
381 {
382     unsigned carry = 0;
383     unsigned N = n;
384 
385     for (unsigned i=0; i<N; i+=1)
386     {
387         unsigned ux = x.get(i);
388         ux += carry;
389 
390         if ( ux >= carry )
391         {
392             unsigned u = get(i);
393             unsigned nu = u - ux;
394             carry = nu > u;
395             set(i,nu);
396         }
397     }
398 }
399 
init(unsigned x)400 void vlong_value::init( unsigned x )
401 {
402     clear();
403     set(0,x);
404 }
405 
copy(vlong_value & x)406 void vlong_value::copy( vlong_value& x )
407 {
408     clear();
409     unsigned i=x.n;
410 
411     while (i)
412     {
413         i -= 1;
414         set( i, x.get(i) );
415     }
416 }
417 
vlong_value()418 vlong_value::vlong_value()
419 {
420     share = 0;
421 }
422 
mul(vlong_value & x,vlong_value & y)423 void vlong_value::mul( vlong_value& x, vlong_value& y )
424 {
425     fast_mul( x, y, x.bits()+y.bits() );
426 }
427 
divide(vlong_value & x,vlong_value & y,vlong_value & rem)428 void vlong_value::divide( vlong_value& x, vlong_value& y, vlong_value& rem )
429 {
430     init(0);
431     rem.copy(x);
432     vlong_value m,s;
433     m.copy(y);
434     s.init(1);
435 
436     while ( rem.cf(m) > 0 )
437     {
438         m.shl();
439         s.shl();
440     }
441 
442     while ( rem.cf(y) >= 0 )
443     {
444         while ( rem.cf(m) < 0 )
445         {
446             m.shr();
447             s.shr();
448         }
449 
450         rem.subtract( m );
451         add( s );
452     }
453 }
454 
455 // Implementation of vlong
456 
load(unsigned * a,unsigned n)457 void vlong::load( unsigned* a, unsigned n )
458 {
459     docopy();
460     value->clear();
461 
462     for (unsigned i=0; i<n; i+=1)
463     {
464         value->set(i,a[i]);
465     }
466 }
467 
store(unsigned * a,unsigned n) const468 void vlong::store( unsigned* a, unsigned n ) const
469 {
470     for (unsigned i=0; i<n; i+=1)
471     {
472         a[i] = value->get(i);
473     }
474 }
475 
get_nunits() const476 unsigned vlong::get_nunits() const
477 {
478     return value->n;
479 }
480 
bits() const481 unsigned vlong::bits() const
482 {
483     return value->bits();
484 }
485 
docopy()486 void vlong::docopy()
487 {
488     if ( value->share )
489     {
490         value->share -= 1;
491         vlong_value* nv = new vlong_value;
492         nv->copy(*value);
493         value = nv;
494     }
495 }
496 
cf(const vlong & x) const497 int vlong::cf( const vlong& x ) const
498 {
499     int neg = negative && !value->is_zero();
500     //int neg2 = x.negative && !x.value->is_zero();
501 
502     if ( neg == (x.negative && !x.value->is_zero()) )
503         //if ( neg == neg2)
504     {
505         return value->cf( *x.value );
506     }
507 
508     else if ( neg )
509     {
510         return -1;
511     }
512     else
513     {
514         return +1;
515     }
516 }
517 
vlong(unsigned x)518 vlong::vlong (unsigned x)
519 {
520     value = new vlong_value;
521     negative = 0;
522     value->init(x);
523 }
524 
vlong(const vlong & x)525 vlong::vlong ( const vlong& x ) // copy constructor
526 {
527     negative = x.negative;
528     value = x.value;
529     value->share += 1;
530 }
531 
operator =(const vlong & x)532 vlong& vlong::operator =(const vlong& x)
533 {
534     if ( value->share )
535     {
536         value->share -=1;
537     }
538     else
539     {
540         delete value;
541     }
542 
543     value = x.value;
544     value->share += 1;
545     negative = x.negative;
546     return *this;
547 }
548 
~vlong()549 vlong::~vlong()
550 {
551     if ( value->share )
552     {
553         value->share -=1;
554     }
555     else
556     {
557         delete value;
558     }
559 }
560 
operator unsigned()561 vlong::operator unsigned () // conversion to unsigned
562 {
563     return *value;
564 }
565 
operator +=(const vlong & x)566 vlong& vlong::operator +=(const vlong& x)
567 {
568     if ( negative == x.negative )
569     {
570         docopy();
571         value->add( *x.value );
572     }
573     else if ( value->cf( *x.value ) >= 0 )
574     {
575         docopy();
576         value->subtract( *x.value );
577     }
578     else
579     {
580         vlong tmp = *this;
581         *this = x;
582         *this += tmp;
583     }
584 
585     return *this;
586 }
587 
operator -=(const vlong & x)588 vlong& vlong::operator -=(const vlong& x)
589 {
590     if ( negative != x.negative )
591     {
592         docopy();
593         value->add( *x.value );
594     }
595     else if ( value->cf( *x.value ) >= 0 )
596     {
597         docopy();
598         value->subtract( *x.value );
599     }
600     else
601     {
602         vlong tmp = *this;
603         *this = x;
604         *this -= tmp;
605         negative = 1 - negative;
606     }
607 
608     return *this;
609 }
610 
operator +(const vlong & x,const vlong & y)611 vlong operator +( const vlong& x, const vlong& y )
612 {
613     vlong result = x;
614     result += y;
615     return result;
616 }
617 
operator -(const vlong & x,const vlong & y)618 vlong operator -( const vlong& x, const vlong& y )
619 {
620     vlong result = x;
621     result -= y;
622     return result;
623 }
624 
operator *(const vlong & x,const vlong & y)625 vlong operator *( const vlong& x, const vlong& y )
626 {
627     vlong result;
628     result.value->mul( *x.value, *y.value );
629     result.negative = x.negative ^ y.negative;
630     return result;
631 }
632 
operator /(const vlong & x,const vlong & y)633 vlong operator /( const vlong& x, const vlong& y )
634 {
635     vlong result;
636     vlong_value rem;
637     result.value->divide( *x.value, *y.value, rem );
638     result.negative = x.negative ^ y.negative;
639     return result;
640 }
641 
642 #if defined(__DEBUG__)
print_vlong(const vlong_value & v,const char * name)643 void print_vlong( const vlong_value& v, const char* name )
644 {
645     printf("%s value(%d): ", name, v.n * sizeof(unsigned int));
646 
647     for (int i = 0; i < v.n; ++i)
648     {
649         printf("%08X", v.a[i]);
650     }
651 
652     printf("\n");
653 }
654 #endif
655 
operator %(const vlong & x,const vlong & y)656 vlong operator %( const vlong& x, const vlong& y )
657 {
658     vlong result;
659     vlong_value divide;
660     divide.divide( *x.value, *y.value, *result.value );
661     result.negative = x.negative; // not sure about this?
662     return result;
663 }
664 /*
665 static vlong gcd( const vlong &X, const vlong &Y )
666 {
667     vlong x=X, y=Y;
668     while (1)
669     {
670         if ( y == (vlong)0 ) return x;
671         x = x % y;
672         if ( x == (vlong)0 ) return y;
673         y = y % x;
674     }
675 }
676 */
677 
modinv(const vlong & a,const vlong & m)678 static vlong modinv( const vlong& a, const vlong& m ) // modular inverse
679 // returns i in range 1..m-1 such that i*a = 1 mod m
680 // a must be in range 1..m-1
681 {
682     vlong j=1,i=0,b=m,c=a,x,y;
683 
684     while ( c != (vlong)0 )
685     {
686         x = b / c;
687         y = b - x*c;
688         b = c;
689         c = y;
690         y = j;
691         j = i - j*x;
692         i = y;
693     }
694 
695     if ( i < (vlong)0 )
696     {
697         i += m;
698     }
699 
700     return i;
701 }
702 
703 class monty // class for montgomery modular exponentiation
704 {
705     vlong R,R1,m,n1;
706     vlong T,k;   // work registers
707     unsigned N;  // bits for R
708     void mul( vlong& x, const vlong& y );
709 public:
710     vlong exp( const vlong& x, const vlong& e );
711     monty( const vlong& M );
712 };
713 
monty(const vlong & M)714 monty::monty( const vlong& M )
715 {
716     m = M;
717     N = 0;
718     R = 1;
719 
720     while ( R < M )
721     {
722         R += R;
723         N += 1;
724     }
725 
726     R1 = modinv( R-m, m );
727     n1 = R - modinv( m, R );
728 }
729 
mul(vlong & x,const vlong & y)730 void monty::mul( vlong& x, const vlong& y )
731 {
732     // T = x*y;
733     T.value->fast_mul( *x.value, *y.value, N*2 );
734 
735     // k = ( T * n1 ) % R;
736     k.value->fast_mul( *T.value, *n1.value, N );
737 
738     // x = ( T + k*m ) / R;
739     x.value->fast_mul( *k.value, *m.value, N*2 );
740     x += T;
741     x.value->shr( N );
742 
743     if (x>=m)
744     {
745         x -= m;
746     }
747 }
748 
exp(const vlong & x,const vlong & e)749 vlong monty::exp( const vlong& x, const vlong& e )
750 {
751     vlong result = R-m, t = ( x * R ) % m;
752     unsigned bits = e.value->bits();
753     unsigned i = 0;
754 
755     while (1)
756     {
757         if ( e.value->test(i) )
758         {
759             mul( result, t);
760         }
761 
762         i += 1;
763 
764         if ( i == bits )
765         {
766             break;
767         }
768 
769         mul( t, t );
770     }
771 
772     return ( result * R1 ) % m;
773 }
774 
modexp(const vlong & x,const vlong & e,const vlong & m)775 static vlong modexp( const vlong& x, const vlong& e, const vlong& m )
776 {
777     monty me(m);
778     return me.exp( x,e );
779 }
780 
781 // RSA.CPP -----------------------------------
782 
encrypt(const vlong & plain)783 vlong public_key::encrypt( const vlong& plain )
784 {
785 #if defined(__DEBUG__)
786 
787     if ( plain >= m )
788     {
789         printf("ERROR: plain too big for this key\n");
790     }
791 
792 #endif
793     return modexp( plain, e, m );
794 }
795 
796 /*
797 vlong private_key::decrypt( const vlong& cipher )
798 {
799     // Calculate values for performing decryption
800     // These could be cached, but the calculation is quite fast
801     vlong d = modinv( e, (p-(vlong)1)*(q-(vlong)1) );
802     vlong u = modinv( p, q );
803     vlong dp = d % (p-(vlong)1);
804     vlong dq = d % (q-(vlong)1);
805 
806     // Apply chinese remainder theorem
807     vlong a = modexp( cipher % p, dp, p );
808     vlong b = modexp( cipher % q, dq, q );
809     if ( b < a ) b += q;
810     return a + p * ( ((b-a)*u) % q );
811 }
812 
813 void vlong_pair_2_str (char *me_str,vlong &m,vlong &e)
814 {
815     const char *hex_str = "0123456789ABCDEF";
816 
817     char tmp_str[MAX_CRYPT_BITS/2+1];
818 
819     unsigned int x;
820     unsigned int me_len = 0;
821     unsigned int i;
822     unsigned int j;
823     vlong m1 = m;
824     vlong e1 = e;
825     vlong zero = 0;
826 
827     i = 0;
828     while (m1 != zero)
829     {
830         x = m1 % (vlong) 16;
831         m1 = m1 / (vlong) 16;
832         tmp_str[i++] = hex_str[x];
833     }
834 
835     for (j=0; j < i; ++j)
836         me_str[me_len++] = tmp_str[i-1-j];
837 
838     me_str[me_len++] = '#';
839 
840     i = 0;
841     while (e1 != zero)
842     {
843         x = e1 %(vlong)16;
844         e1 = e1 / (vlong)16;
845         tmp_str[i++] = hex_str[x];
846     }
847 
848     for (j=0; j < i; ++j)
849         me_str[me_len++] = tmp_str[i-1-j];
850 
851     me_str[me_len] = 0;
852 }
853 */
854 
str_2_vlong_pair(const char * me_str,vlong & m,vlong & e)855 void str_2_vlong_pair (const char* me_str,vlong& m,vlong& e)
856 {
857     int i;
858     int dash_pos = 0;
859     m = 0;
860     e = 0;
861 
862     int me_len = (int)strlen (me_str);
863 
864     for (i = me_len-1; i>0; --i)
865         if (me_str[i] == '#')
866         {
867             dash_pos = i;
868             break;
869         }
870 
871     if (dash_pos == 0)
872     {
873         return;
874     }
875 
876 
877     for (i = 0; i<dash_pos; ++i)
878     {
879         m = m * (vlong)16;
880 
881         if (me_str[i] > '9')
882         {
883             m = m + (vlong) (me_str[i]-'A'+10);
884         }
885         else
886         {
887             m = m + (vlong) (me_str[i]-'0');
888         }
889     }
890 
891     for (i = dash_pos+1; i<me_len; ++i)
892     {
893         e = e * (vlong)16;
894 
895         if (me_str[i] > '9')
896         {
897             e = e + (vlong) (me_str[i]-'A'+10);
898         }
899         else
900         {
901             e = e + (vlong) (me_str[i]-'0');
902         }
903     }
904 
905 
906 }
907 
908 /*
909 void private_key::MakeMeStr(char * me_str)
910 {
911     vlong_pair_2_str (me_str,m,e);
912 }
913 
914 void private_key::MakePqStr(char * me_str)
915 {
916     vlong_pair_2_str (me_str,p,q);
917 }
918 
919 
920 void private_key::MakePq (const char *me_str)
921 {
922     str_2_vlong_pair (me_str,p,q);
923     {
924     m = p*q;
925     e = 50001; // must be odd since p-1 and q-1 are even
926     while ( gcd(p-(vlong)1,e) != (vlong)1 || gcd(q-(vlong)1,e) != (vlong)1 ) e += 2;
927     }
928 
929 }
930 */
931 
MakeMe(const char * me_str)932 void public_key::MakeMe(const char* me_str)
933 {
934     str_2_vlong_pair (me_str,m,e);
935 }
936 
CCryptoProviderRSA()937 CCryptoProviderRSA::CCryptoProviderRSA()
938 {
939 }
940 
~CCryptoProviderRSA()941 CCryptoProviderRSA::~CCryptoProviderRSA()
942 {
943 }
944 
_rmemcpy(char * dst,const char * src,size_t size)945 void inline _rmemcpy (char* dst,const char* src,size_t size)
946 {
947     src += size;
948 
949     while (size--)
950     {
951         *dst++ = *(--src);
952     }
953 }
954 /*
955 void CCryptoProviderRSA::GetBlockSize(int &enbs, int &debs)
956 {
957     enbs=0;
958     debs=0;
959 }
960 */
EncryptPortion(const char * pt,size_t pt_size,char * ct,size_t & ct_size)961 void CCryptoProviderRSA::EncryptPortion(const char* pt, size_t pt_size, char* ct, size_t& ct_size)
962 {
963     vlong plain, cipher;
964 
965     const size_t bytes_per_unit = BPU / 8;
966 
967     size_t padding = (pt_size & 3) ? (4 - (pt_size & 3)) : 0;
968     char tmp[MAX_CRYPT_BITS/4];
969 
970     // ensure big-endianness
971     _rmemcpy(tmp, pt, pt_size);
972     memset(tmp + pt_size, 0, padding);
973     plain.load(reinterpret_cast<unsigned int*>(tmp), (int)(pt_size+padding) / bytes_per_unit);
974 
975     cipher = prkface.encrypt(plain);
976     ct_size = cipher.get_nunits() * bytes_per_unit;
977 
978     // ensure big-endianness
979     cipher.store(reinterpret_cast<unsigned int*>(tmp), (int)ct_size / bytes_per_unit);
980     _rmemcpy(ct, tmp, ct_size);
981 }
982 
983 /*
984 void CCryptoProviderRSA::DecryptPortion(const char *ct, size_t ct_size, char *pt, size_t &pt_size)
985 {
986     vlong plain, cipher;
987 
988     const size_t bytes_per_unit = BPU / 8;
989 
990     char tmp[MAX_CRYPT_BITS/4];
991 
992     // ensure big-endianness
993     _rmemcpy(tmp, ct, ct_size);
994 
995     cipher.load((unsigned int*)tmp, (int)ct_size / bytes_per_unit);
996     plain = prkface.decrypt(cipher);
997 
998     // ensure big-endianness
999     plain.store((unsigned int*)tmp, plain.get_nunits());
1000     _rmemcpy(pt, tmp, pt_size);
1001 }
1002 */
1003 
ImportPublicKey(const char * pk)1004 void CCryptoProviderRSA::ImportPublicKey(const char* pk)
1005 {
1006     prkface.MakeMe(pk);
1007 }
1008 
1009 /*
1010 void CCryptoProviderRSA::ImportPrivateKey(const char *pk)
1011 {
1012     prkface.MakePq(pk);
1013 }
1014 
1015 void CCryptoProviderRSA::ExportPublicKey(char *pk)
1016 {
1017     prkface.MakeMeStr(pk);
1018 }
1019 
1020 void CCryptoProviderRSA::ExportPrivateKey(char *pk)
1021 {
1022     prkface.MakePqStr(pk);
1023 }
1024 
1025 #if defined(__DEBUG__)
1026 void printbuf(const char * buf, int size)
1027 {
1028     for(const char * p = buf; p < buf + size; ++p)
1029     {
1030         printf("%02X", *p & 0x000000ff);
1031     }
1032     printf("\n");
1033 }
1034 #endif
1035 */
1036 
Encrypt(const char * inbuf,size_t in_size,char * outbuf,size_t & out_size)1037 void CCryptoProviderRSA::Encrypt(const char* inbuf, size_t in_size,char* outbuf, size_t& out_size)
1038 {
1039     size_t i,cp_size;
1040 
1041     char portbuf[MAX_CRYPT_BITS/8];
1042     char cpbuf[MAX_CRYPT_BITS/4];
1043     const char* inp = inbuf;
1044 
1045     unsigned short lm;
1046 
1047     // must ensure that any data block would be < key's modulus
1048     // hence -1
1049     int portion_len = (prkface.m.bits() - 1)  / 8;
1050 
1051     if (portion_len < 0) portion_len = 0;
1052 
1053     char* prev_crypted = new char[portion_len];
1054     memset(prev_crypted, 0, portion_len);
1055 
1056     out_size = 0;
1057 
1058     while (in_size)
1059     {
1060         size_t uportion_len = (std::size_t) (portion_len);
1061         size_t cur_size     = in_size > uportion_len ? uportion_len : in_size;
1062 
1063         for (i=0; i<cur_size; ++i)
1064         {
1065             portbuf[i] = inp[i] ^ prev_crypted[i];
1066         }
1067 
1068         EncryptPortion(portbuf, cur_size, cpbuf, cp_size);
1069 
1070         for (i=0; i< uportion_len; ++i)
1071         {
1072             prev_crypted[i] = i < cp_size ? cpbuf[i] : 0;
1073         }
1074 
1075         lm=cur_size;
1076         memcpy (outbuf+out_size,&lm, sizeof(unsigned short));
1077         out_size+=sizeof (unsigned short);
1078         lm=(unsigned short)cp_size;
1079         memcpy (outbuf+out_size,&lm, sizeof(unsigned short));
1080         out_size+=sizeof (unsigned short);
1081         memcpy (outbuf+out_size,cpbuf, cp_size);
1082         out_size+=cp_size;
1083         inp+=cur_size;
1084         in_size-=cur_size;
1085     }
1086 
1087     delete [] prev_crypted;
1088     return;
1089 }
1090 
1091 /*
1092 void CCryptoProviderRSA::Decrypt(const char *inbuf, size_t in_size,char *outbuf, size_t &out_size)
1093 {
1094     size_t i, cp_size,pt_size;
1095 
1096     char portbuf[MAX_CRYPT_BITS/8];
1097     char cpbuf[MAX_CRYPT_BITS/4];
1098 
1099     unsigned short lmi, lmo;
1100 
1101     // must ensure that any data block would be < key's modulus
1102     // hence -1
1103     // TODO: size_t here ?
1104     int portion_len = (prkface.m.bits() - 1)  / 8;
1105     char prev_crypted[portion_len];
1106     memset(&prev_crypted, 0, portion_len);
1107 
1108     const char *inp=inbuf;
1109     out_size = 0;
1110 
1111     while(in_size)
1112     {
1113         memcpy (&lmi,inp,sizeof (unsigned short)); inp += sizeof(unsigned short); in_size -= sizeof(unsigned short);
1114         memcpy (&lmo,inp,sizeof (unsigned short)); inp += sizeof(unsigned short); in_size -= sizeof(unsigned short);
1115 
1116         if (lmo>in_size)
1117             break;
1118 
1119         memcpy (cpbuf,inp,lmo);
1120         cp_size = lmo;
1121         pt_size = lmi;
1122 
1123         DecryptPortion(cpbuf, cp_size, portbuf, pt_size);
1124 
1125         if (lmi>pt_size)
1126             lmi=(unsigned short)pt_size;
1127 
1128         for (i=0; i<lmi; ++i)
1129             portbuf[i] ^= prev_crypted[i];
1130 
1131         for (i=0; i< portion_len; ++i)
1132             prev_crypted[i] = i < cp_size ? cpbuf[i] : 0;
1133 
1134         memcpy (outbuf+out_size,portbuf,lmi);
1135         out_size += lmi;
1136 
1137         inp+=lmo;
1138         in_size-=lmo;
1139     }
1140     return;
1141 }
1142 */
1143 
1144 } // namespace YandexAuth
1145