5 of 8 incorporated comment into question body

Twofish fails Dieharder test

I've tested Twofish (256 bit) as follows. A lengthy pseudorandom sequence was generated and used as a key. Plaintext phrases 000000000..00, 00000..01, 0000...FFFFF, were generated and encoded using Twofish with the key. Ciphertexts were split in 32 bit numbers (40 million numbers total).

In theory, the cipher should pass the Dieharder tests. In practice, it appears to fail a number of them.

Pseudorandom number generator passed all tests, so this isn't a bug with Dieharder.

Does this mean that Twofish is not as secure as claimed?


Edited:

TwoFish.java comes from http://www.sethi.org/tmp/ssh/src/com/mindbright/security/cipher/Twofish.java

FishRunner.java is my wrapper that generates "sequential plain text blocks as ASCII characters". Each block is ciphered using Twofish with byte[] defaultKey = {-24,29,83,38,-77,-92,-46,25,-117,-71,42,-44,-52,97,58,-114,50,-27,49,47,12,52,-76,-88,-26,17,18,84,30,-95,80,13,32};. From each plaintext block I get 256 bits of ciphered text. These 256 bits are split in chunks of 32 bit each and saved to "/tmp/FromFish/fish.txt" with an appropriate header.

first several lines of fish.txt

#==================================================================
# generator mt19937  seed = 316179543
#==================================================================
type: d
count: 40000000
numbit: 32
4205098517
1950644630
 217236044
4021751533
1670623305
4216006007
1982760947
2956150679
2523872870
1802016715
 546984380
3195151793
 478820823
3432394711

Once all 40000000 records were created (440Mb of data) Dieharder was launched with dieharder -a -g 202 -f fish.txt >>res.txt

            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
##  
   rng_name    |           filename             |rands/second|
     file_input|                        fish.txt|  7.26e+06  |
#   
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
# b       #
   diehard_birthdays|   0|       100|     100|0.65344498|  PASSED     
      diehard_operm5|   0|   1000000|     100|0.11726095|  PASSED     
  diehard_rank_32x32|   0|     40000|     100|0.84203088|  PASSED     
    diehard_rank_6x8|   0|    100000|     100|0.73796762|  PASSED     
   diehard_bitstream|   0|   2097152|     100|0.38051493|  PASSED      
        diehard_opso|   0|   2097152|     100|0.04995365|  PASSED      
        diehard_oqso|   0|   2097152|     100|0.59990831|  PASSED      
         diehard_dna|   0|   2097152|     100|0.62220146|  PASSED      
diehard_count_1s_str|   0|    256000|     100|0.86262588|  PASSED       
diehard_count_1s_byt|   0|    256000|     100|0.12560712|  PASSED       
 diehard_parking_lot|   0|     12000|     100|0.28041223|  PASSED       
    diehard_2dsphere|   2|      8000|     100|0.76183470|  PASSED       
    diehard_3dsphere|   3|      4000|     100|0.17846568|  PASSED       
     diehard_squeeze|   0|    100000|     100|0.00384865|   WEAK        
        diehard_sums|   0|       100|     100|0.43470008|  PASSED       
        diehard_runs|   0|    100000|     100|0.70560801|  PASSED         
        diehard_runs|   0|    100000|     100|0.98961342|  PASSED       
       diehard_craps|   0|    200000|     100|0.18043071|  PASSED        
       diehard_craps|   0|    200000|     100|0.89290364|  PASSED       
 marsaglia_tsang_gcd|   0|  10000000|     100|0.00000000|  FAILED        
 marsaglia_tsang_gcd|   0|  10000000|     100|0.00000000|  FAILED       
         sts_monobit|   1|    100000|     100|0.72613955|  PASSED        
            sts_runs|   2|    100000|     100|0.26712378|  PASSED        
          sts_serial|   1|    100000|     100|0.94935591|  PASSED        
          sts_serial|   2|    100000|     100|0.93198856|  PASSED       
          sts_serial|   3|    100000|     100|0.99554380|   WEAK          
          sts_serial|   3|    100000|     100|0.72444970|  PASSED         
          sts_serial|   4|    100000|     100|0.19981717|  PASSED          
          sts_serial|   4|    100000|     100|0.06124493|  PASSED        
          sts_serial|   5|    100000|     100|0.87811046|  PASSED       
          sts_serial|   5|    100000|     100|0.09618787|  PASSED        
          sts_serial|   6|    100000|     100|0.87317579|  PASSED       
          sts_serial|   6|    100000|     100|0.99688012|   WEAK         
          sts_serial|   7|    100000|     100|0.50043383|  PASSED        
          sts_serial|   7|    100000|     100|0.61746527|  PASSED       
          sts_serial|   8|    100000|     100|0.97376805|  PASSED        
          sts_serial|   8|    100000|     100|0.94872352|  PASSED        
          sts_serial|   9|    100000|     100|0.35958803|  PASSED        
          sts_serial|   9|    100000|     100|0.39252366|  PASSED        
          sts_serial|  10|    100000|     100|0.40682407|  PASSED       
          sts_serial|  10|    100000|     100|0.69846273|  PASSED      
          sts_serial|  11|    100000|     100|0.14757958|  PASSED      
          sts_serial|  11|    100000|     100|0.85142983|  PASSED     
          sts_serial|  12|    100000|     100|0.33628714|  PASSED   
          sts_serial|  12|    100000|     100|0.80400201|  PASSED       
          sts_serial|  13|    100000|     100|0.50635238|  PASSED     
          sts_serial|  13|    100000|     100|0.04113439|  PASSED         
          sts_serial|  14|    100000|     100|0.48030593|  PASSED    
          sts_serial|  14|    100000|     100|0.83615004|  PASSED   
          sts_serial|  15|    100000|     100|0.85634237|  PASSED    
          sts_serial|  15|    100000|     100|0.86413582|  PASSED     
          sts_serial|  16|    100000|     100|0.81247787|  PASSED    
          sts_serial|  16|    100000|     100|0.62279344|  PASSED   
         rgb_bitdist|   1|    100000|     100|0.10521730|  PASSED    
         rgb_bitdist|   2|    100000|     100|0.36419006|  PASSED   
         rgb_bitdist|   3|    100000|     100|0.50848488|  PASSED   
         rgb_bitdist|   4|    100000|     100|0.91911028|  PASSED   
         rgb_bitdist|   5|    100000|     100|0.68355135|  PASSED   
         rgb_bitdist|   6|    100000|     100|0.07298074|  PASSED   
         rgb_bitdist|   7|    100000|     100|0.99703911|   WEAK    
         rgb_bitdist|   8|    100000|     100|0.50843903|  PASSED   
         rgb_bitdist|   9|    100000|     100|0.51151893|  PASSED   
         rgb_bitdist|  10|    100000|     100|0.40558627|  PASSED   
         rgb_bitdist|  11|    100000|     100|0.27640943|  PASSED   
         rgb_bitdist|  12|    100000|     100|0.64415540|  PASSED   
rgb_minimum_distance|   2|     10000|    1000|0.77930849|  PASSED   
rgb_minimum_distance|   3|     10000|    1000|0.89974521|  PASSED   
rgb_minimum_distance|   4|     10000|    1000|0.52655953|  PASSED   
rgb_minimum_distance|   5|     10000|    1000|0.01029230|  PASSED   
    rgb_permutations|   2|    100000|     100|0.49947588|  PASSED    
    rgb_permutations|   3|    100000|     100|0.48976917|  PASSED   
    rgb_permutations|   4|    100000|     100|0.99435735|  PASSED   
    rgb_permutations|   5|    100000|     100|0.18313717|  PASSED   
      rgb_lagged_sum|   0|   1000000|     100|0.11846988|  PASSED   
      rgb_lagged_sum|   1|   1000000|     100|0.20793259|  PASSED   
      rgb_lagged_sum|   2|   1000000|     100|0.08406645|  PASSED   
      rgb_lagged_sum|   3|   1000000|     100|0.00002903|   WEAK    
      rgb_lagged_sum|   4|   1000000|     100|0.00000000|  FAILED   
      rgb_lagged_sum|   5|   1000000|     100|0.00156593|   WEAK    
      rgb_lagged_sum|   6|   1000000|     100|0.13398055|  PASSED   
      rgb_lagged_sum|   7|   1000000|     100|0.00000071|  FAILED  
      rgb_lagged_sum|   8|   1000000|     100|0.07282751|  PASSED   
      rgb_lagged_sum|   9|   1000000|     100|0.00000653|   WEAK    
      rgb_lagged_sum|  10|   1000000|     100|0.24179580|  PASSED   
      rgb_lagged_sum|  11|   1000000|     100|0.00620851|  PASSED   
      rgb_lagged_sum|  12|   1000000|     100|0.24310357|  PASSED   
      rgb_lagged_sum|  13|   1000000|     100|0.15323532|  PASSED   
      rgb_lagged_sum|  14|   1000000|     100|0.00000174|   WEAK    
      rgb_lagged_sum|  15|   1000000|     100|0.00000000|  FAILED   
      rgb_lagged_sum|  16|   1000000|     100|0.39385345|  PASSED   
      rgb_lagged_sum|  17|   1000000|     100|0.11381934|  PASSED   
      rgb_lagged_sum|  18|   1000000|     100|0.78715021|  PASSED   
      rgb_lagged_sum|  19|   1000000|     100|0.00000000|  FAILED   
      rgb_lagged_sum|  20|   1000000|     100|0.52371093|  PASSED   
      rgb_lagged_sum|  21|   1000000|     100|0.00531931|  PASSED   
      rgb_lagged_sum|  22|   1000000|     100|0.19857791|  PASSED   
      rgb_lagged_sum|  23|   1000000|     100|0.00000000|  FAILED   
      rgb_lagged_sum|  24|   1000000|     100|0.00000431|   WEAK    
      rgb_lagged_sum|  25|   1000000|     100|0.02471464|  PASSED   
      rgb_lagged_sum|  26|   1000000|     100|0.07546643|  PASSED   
      rgb_lagged_sum|  27|   1000000|     100|0.01786362|  PASSED   
      rgb_lagged_sum|  28|   1000000|     100|0.28778610|  PASSED   
      rgb_lagged_sum|  23|   1000000|     100|0.00000000|  FAILED 
      rgb_lagged_sum|  30|   1000000|     100|0.13632978|  PASSED   
      rgb_lagged_sum|  31|   1000000|     100|0.00000000|  FAILED   
      rgb_lagged_sum|  32|   1000000|     100|0.11176539|  PASSED   
     rgb_kstest_test|   0|     10000|    1000|0.29113864|  PASSED   
     dab_bytedistrib|   0|  51200000|       1|0.00000000|  FAILED   
             dab_dct| 256|     50000|       1|0.93719430|  PASSED   
Preparing to run test 207.  ntuple = 0 
        dab_filltree|  32|  15000000|        1|0.60930301|  PASSED  
        dab_filltree|  32|  15000000|       1|0.29252232|  PASSED     
Preparing to run test 208.  ntuple = 0   
       dab_filltree2|   0|   5000000|       1|0.64246455|  PASSED     
       dab_filltree2|   1|   5000000|       1|0.20829118|  PASSED     
Preparing to run test 209.  ntuple = 0
        dab_monobit2|  12|  65000000|       1|1.00000000|  FAILED     

Here's a summary of the tests that failed:

       test_name   |ntup| tsamples |psamples|  p-value |Assessment
marsaglia_tsang_gcd|   0|  10000000|     100|0.00000000|  FAILED         
marsaglia_tsang_gcd|   0|  10000000|     100|0.00000000|  FAILED
     rgb_lagged_sum|   7|   1000000|     100|0.00000071|  FAILED
     rgb_lagged_sum|  15|   1000000|     100|0.00000000|  FAILED
     rgb_lagged_sum|  19|   1000000|     100|0.00000000|  FAILED
     rgb_lagged_sum|  23|   1000000|     100|0.00000000|  FAILED
     rgb_lagged_sum|  31|   1000000|     100|0.00000000|  FAILED 
    dab_bytedistrib|   0|  51200000|       1|0.00000000|  FAILED
       dab_monobit2|  12|  65000000|       1|1.00000000|  FAILED

Twofish algo is saved here: https://pastebin.com/THGegxKY

Class below is my wrapper to generate ciphers from consequential plain text messages

package models;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.util.Arrays;
import java.util.Random;

public class FishRunner {

    private int keySize = 32;
    private int numberOfReps = 10000000;
    private byte[] defaultKey = {-24,29,83,38,-77,-92,-46,25,-117,-71,42,-44,-52,97,58,-114,50,-27,49,47,12,52,-76,-88,-26,17,18,84,30,-95,80,13,32};


    public static void main(String[] args) {

        System.out.println("l: " + fS(toUnsignedLong(-1)) +", 2xMaxInt "+ (2* ((long) Integer.MAX_VALUE))  +"\n\n\n");      

        FishRunner fr = new FishRunner();

        fr.testAlgo();

    }

    private void testAlgo() {


        byte[] keyChars = initKey();

        //System.out.println("                 key:     " + toString(keyChars));

        PrintWriter writer;
        try {

            int lineCount = numberOfReps*4;
            writer = new PrintWriter("/tmp/FromFish/fish.txt", "UTF-8");

            writer.println("#==================================================================");
            writer.println("# generator mt19937  seed = 316179543");
            writer.println("#==================================================================");
            writer.println("type: d");
            writer.println("count: "+lineCount+"");
            writer.println("numbit: 32");

        for(int i = 0; i < numberOfReps; i++) {

            byte[] text = generateText(i);
            //System.out.println("                 text:     " + toString(text));
            try {
                Object key = MyFish.makeKey(keyChars);  
                byte[] ct = MyFish.blockEncrypt(text, 0, key);
                for (int x = 0; x < ct.length ; x=x+4) {
                    //System.out.println(fS(Long.toString(toUnsignedLong(toInt(ct, x))),10));
                    writer.println(fS(Long.toString(toUnsignedLong(toInt(ct, x))),10));

                }

            } catch (InvalidKeyException e) {   e.printStackTrace(); }

        }

        //writer.println("The first line");
        //writer.println("The second line");
        writer.close();


    } catch (FileNotFoundException | UnsupportedEncodingException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }


        // TODO Auto-generated method stub

    }


    private byte[] generateText(int stepNumber) {

        byte[] text = new byte[32];

        text[0] = (byte) (stepNumber );
        text[1] = (byte) (stepNumber >>> 8);
        text[2] = (byte) (stepNumber >>> 16);
        text[3] = (byte) (stepNumber >>> 24);
        return text;

        }


    private byte[] initKey() {

        Random r = new Random(0);
        byte[] key = new byte[keySize];

        for (int i = 0; i <  keySize; i++) {            
            key[i] = (byte)(-128+r.nextInt(256)) ;  
        }
        System.out.println("Key: "+Arrays.toString(key));

    return key;

    }

    private void testFish() {   

        byte[] key = new byte[keySize];

        for (int i = 0; i < keySize; i++)
            key[i] = (byte) defaultKey[i];      

    }       

    public static int toInt(byte[] bytes, int offset) {

        //System.out.print("i             ret             (ret <<= 8)       (int)(bytes[i])    (& 0xFF)\n");
          int ret = 0;
          for (int i=0; i<4 && i+offset<bytes.length; i++) {
            //  System.out.print(fS(i)+ " " + fS(ret) );
            ret <<= 8;
           // System.out.print(fS(ret)  + "  "+ fS( (int)(bytes[i]) )+ "");
            ret |= (int)bytes[i+offset] & 0xFF;
            //System.out.print(", (& 0xFF)" + fS(ret)  +"\n");

          }

          return ret;
        }


    public static long toUnsignedLong(int x) {
        return x & 0x00000000ffffffffL;
    }

       private static final char[] HEX_DIGITS = {                 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'              };

       private static String toString (byte[] ba, int offset, int length) {
              char[] buf = new char[length * 2];
              for (int i = offset, j = 0, k; i < offset+length; ) {
                 k = ba[i++];
                 buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F];
                 buf[j++] = HEX_DIGITS[ k      & 0x0F];
              }
              return new String(buf);
           }




       //        INNER METHODS

       private static final int longSpaces = 35;
        private static final int intSpaces = 15;



        public static String fS(long text) {    
            return fS(Long.toString(text), longSpaces);
        }

        public static String fS(int text) { 
            return fS(Integer.toString(text), intSpaces);
        }

        public static String fS(String text, int charTotal) {       
            return String.format("%1$" + charTotal + "s",text + "" );
        }


           private static String toString (byte[] ba) {
                  return toString(ba, 0, ba.length);
               }

        private void chk() {

            long mL = (long) Integer.MAX_VALUE;
            mL= mL*2;

            System.out.println("l: " + fS(toUnsignedLong(-1)) +", 2xMaxInt "+ mL  +"\n\n\n");


            for (int x = 0; x < defaultKey.length ; x=x+4) {        
                //toLong(defaultKey, x);

                System.out.println("l: " + fS(toUnsignedLong(toInt(defaultKey, x))));
            }

        }
}