@@ -50,6 +50,11 @@ public KaitaiStream(byte[] data) : base(new MemoryStream(data))
5050 /// </summary>
5151 static readonly bool IsLittleEndian = BitConverter . IsLittleEndian ;
5252
53+ static KaitaiStream ( )
54+ {
55+ compute_single_rotations ( ) ;
56+ }
57+
5358 #endregion
5459
5560 #region Stream positioning
@@ -520,40 +525,107 @@ public byte[] ProcessXor(byte[] data, byte[] key)
520525 int kl = key . Length ;
521526 byte [ ] result = new byte [ dl ] ;
522527
523- for ( int i = 0 , j = 0 ; i < dl ; i ++ , j = i % kl )
528+ for ( int i = 0 ; i < dl ; i ++ )
524529 {
525- result [ i ] = ( byte ) ( data [ i ] ^ key [ j ] ) ;
530+ result [ i ] = ( byte ) ( data [ i ] ^ key [ i % kl ] ) ;
526531 }
527532 return result ;
528533 }
529534
535+ /// <summary>
536+ /// Used internally.
537+ /// </summary>
538+ private static byte [ ] [ ] precomputed_single_rotations ;
539+
540+ /// <summary>
541+ /// Used internally.
542+ /// </summary>
543+ private static void compute_single_rotations ( )
544+ {
545+ precomputed_single_rotations = new byte [ 8 ] [ ] ;
546+ for ( int amount = 1 ; amount < 8 ; amount ++ )
547+ {
548+ byte [ ] translate = new byte [ 256 ] ;
549+ for ( int i = 0 ; i < 256 ; i ++ )
550+ {
551+ // formula taken from: http://stackoverflow.com/a/812039
552+ translate [ i ] = ( byte ) ( ( i << amount ) | ( i >> ( 8 - amount ) ) ) ;
553+ }
554+ precomputed_single_rotations [ amount ] = translate ;
555+ }
556+ }
557+
530558 /// <summary>
531559 /// Perform circular left rotation shift for a given data by a given amount of bits.
532560 /// Pass a negative amount to rotate right.
561+ /// WARNING: May return same byte array if amount is zero (modulo-wise).
533562 /// </summary>
534563 /// <param name="data">The data to rotate, as byte array</param>
535- /// <param name="amount">The amount to rotate by (in bits), as integer</param>
536- /// <param name="groupSize">The size of group in which rotation happens, as non-negative integer</param>
564+ /// <param name="amount">The amount to rotate by (in bits), as integer, negative for right rotation </param>
565+ /// <param name="groupSize">The size of group in which rotation happens, as positive integer</param>
537566 public byte [ ] ProcessRotateLeft ( byte [ ] data , int amount , int groupSize )
538567 {
539- if ( amount > 7 || amount < - 7 ) throw new ArgumentException ( "Rotation of more than 7 cannot be performed." , "amount" ) ;
540- if ( amount < 0 ) amount += 8 ; // Rotation of -2 is the same as rotation of +6
568+ if ( groupSize < 1 )
569+ throw new Exception ( "group size must be at least 1 to be valid" ) ;
570+
571+ amount = Mod ( amount , groupSize * 8 ) ;
572+ if ( amount == 0 )
573+ return data ;
574+
575+ int amount_bytes = amount / 8 ;
576+ int dl = data . Length ;
577+ byte [ ] result = new byte [ dl ] ;
541578
542- byte [ ] r = new byte [ data . Length ] ;
543- switch ( groupSize )
579+ if ( groupSize == 1 )
544580 {
545- case 1 :
546- for ( int i = 0 ; i < data . Length ; i ++ )
581+ byte [ ] translate = precomputed_single_rotations [ amount ] ;
582+
583+ for ( int i = 0 ; i < dl ; i ++ )
584+ {
585+ result [ i ] = translate [ data [ i ] ] ;
586+ }
587+ return result ;
588+ }
589+
590+ if ( dl % groupSize != 0 )
591+ throw new Exception ( "data length must be a multiple of group size" ) ;
592+
593+ if ( amount % 8 == 0 )
594+ {
595+ int [ ] indices = new int [ groupSize ] ;
596+ for ( int i = 0 ; i < groupSize ; i ++ )
597+ {
598+ indices [ i ] = ( i + amount_bytes ) % groupSize ;
599+ }
600+ for ( int i = 0 ; i < dl ; i += groupSize )
601+ {
602+ for ( int k = 0 ; k < groupSize ; k ++ )
547603 {
548- byte bits = data [ i ] ;
549- // http://stackoverflow.com/a/812039
550- r [ i ] = ( byte ) ( ( bits << amount ) | ( bits >> ( 8 - amount ) ) ) ;
604+ result [ i + k ] = data [ i + indices [ k ] ] ;
551605 }
552- break ;
553- default :
554- throw new NotImplementedException ( string . Format ( "Unable to rotate a group of {0} bytes yet" , groupSize ) ) ;
606+ }
607+ return result ;
608+ }
609+
610+ {
611+ int amount1 = amount % 8 ;
612+ int amount2 = 8 - amount1 ;
613+ int [ ] indices1 = new int [ groupSize ] ;
614+ int [ ] indices2 = new int [ groupSize ] ;
615+ for ( int i = 0 ; i < groupSize ; i ++ )
616+ {
617+ indices1 [ i ] = ( i + amount_bytes ) % groupSize ;
618+ indices2 [ i ] = ( i + 1 + amount_bytes ) % groupSize ;
619+ }
620+ for ( int i = 0 ; i < dl ; i += groupSize )
621+ {
622+ for ( int k = 0 ; k < groupSize ; k ++ )
623+ {
624+ result [ i + k ] = ( byte ) ( ( data [ i + indices1 [ k ] ] << amount1 ) | ( data [ i + indices2 [ k ] ] >> amount2 ) ) ;
625+ }
626+ }
627+ return result ;
555628 }
556- return r ;
557629 }
558630
559631 /// <summary>
0 commit comments