@@ -50,6 +50,11 @@ public KaitaiStream(byte[] data) : base(new MemoryStream(data))
50
50
/// </summary>
51
51
static readonly bool IsLittleEndian = BitConverter . IsLittleEndian ;
52
52
53
+ static KaitaiStream ( )
54
+ {
55
+ compute_single_rotations ( ) ;
56
+ }
57
+
53
58
#endregion
54
59
55
60
#region Stream positioning
@@ -520,40 +525,107 @@ public byte[] ProcessXor(byte[] data, byte[] key)
520
525
int kl = key . Length ;
521
526
byte [ ] result = new byte [ dl ] ;
522
527
523
- for ( int i = 0 , j = 0 ; i < dl ; i ++ , j = i % kl )
528
+ for ( int i = 0 ; i < dl ; i ++ )
524
529
{
525
- result [ i ] = ( byte ) ( data [ i ] ^ key [ j ] ) ;
530
+ result [ i ] = ( byte ) ( data [ i ] ^ key [ i % kl ] ) ;
526
531
}
527
532
return result ;
528
533
}
529
534
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
+
530
558
/// <summary>
531
559
/// Perform circular left rotation shift for a given data by a given amount of bits.
532
560
/// Pass a negative amount to rotate right.
561
+ /// WARNING: May return same byte array if amount is zero (modulo-wise).
533
562
/// </summary>
534
563
/// <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>
537
566
public byte [ ] ProcessRotateLeft ( byte [ ] data , int amount , int groupSize )
538
567
{
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 ] ;
541
578
542
- byte [ ] r = new byte [ data . Length ] ;
543
- switch ( groupSize )
579
+ if ( groupSize == 1 )
544
580
{
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 ++ )
547
603
{
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 ] ] ;
551
605
}
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 ;
555
628
}
556
- return r ;
557
629
}
558
630
559
631
/// <summary>
0 commit comments