2017-10-26 13 views
2

私は独自のASN.1フレームワークを実装しています。最後のアイテムはASN.1 RealとしてJava Doubleをエンコードしています。最初のリンクは私のライブラリで、ASN.1 Realsの仕様へのリンクです。私の問題は、正しい仮数にアクセスするencodeDoubleValueです。助けて!エンコードjava double asn1 Real {sign、mantissa、base、exponent}

https://github.com/ZiroZimbarra/ASN1 
レアルのための私のテストで

https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#%5B%7B%22num%22%3A41%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22FitH%22%7D%2C519%5D

私のコードは次のようになります。

testRealBytes(new byte[] {9, 5, (byte) 0x80, (byte) 0xFE, (byte) 0x55, (byte) 0x55, (byte) 0x55}, 1398101.25); 

はここに私の問題は、コードのthridラインでエンコーディングで発生する私のテスト実装、です。ここで

private void testRealBytes(byte[] bytes, Object testObj) throws IOException, InstantiationException, IllegalAccessException { 
    Object obj = (Double) ASN1InputStream.decode(bytes); 
    assertTrue(obj.equals(testObj)); 
    byte[] newBytes = ASN1OutputStream.encodeObject(obj); 
    assertTrue(Arrays.equals(bytes, newBytes)); 
} 

私encodeValue方法である:

public void encodeDoubleValue(Double doubleObj, ASN1OutputStream derStream) throws IOException { 
    if(doubleObj == 0) {return; } 
    if(doubleObj == Double.POSITIVE_INFINITY) { derStream.write(0x40); return; } 
    if(doubleObj == Double.NEGATIVE_INFINITY) { derStream.write(0x41); return; } 
    long bits = Double.doubleToLongBits(doubleObj); 
    long mantissa = (bits & 0x000fffffffffffffL); 
    int exponent = Integer.valueOf(Long.valueOf(((bits & 0x7FF0000000000000L) >> 52) - 1023).toString()); 
    int base = 2; 
    byte signByte = (byte) (((bits & 0x8000000000000000L) > 1) ? 0x40 : 0x00); 
    ASN1OutputStream exponentStream = derStream.newStream(); 
    new ASN1IntegerType().encodeValue(exponent, exponentStream); 
    byte[] exponentBytes = exponentStream.toByteArray(); 
    switch(exponentBytes.length) { 
     case 1: 
      derStream.write(0x80 | (byte) signByte | 0x00); 
      break; 
     case 2: 
      derStream.write(0x80 | (byte) signByte | 0x01); 
      break; 
     case 3: 
      derStream.write(0x80 | (byte) signByte | 0x02); 
      break; 
     default: 
      derStream.write(0x80 | (byte) signByte | 0x03); 
      derStream.write(exponentBytes.length); 
      break; 
    } 
    derStream.write(exponentBytes); 

    byte[] leftBytes = Long.toUnsignedString(mantissa, 16).getBytes(); 
    int length = leftBytes.length; 
    byte[] mantissaBytes = new byte[length]; 
    for(int i = 0; i < length; i++) { 
     mantissaBytes[i] = leftBytes[length - i - 1]; 
    } 
    for(byte b : mantissaBytes) { 
     derStream.write(b); 
    } 
} 

1398101.25ための結果は

[9, 15, -128, 20, 48, 48, 48, 48, 48, 48, 48, 52, 53, 53, 53, 53, 53] 

の代わりに、何それはまた

[9, 5, -128, -2, 85, 85, 85] 
+0

を私は上のベース16への私の変更のために編集toUnsignedString(仮数、16)を呼び出します。 –

+1

いくつかの具体的な質問をし、あなたが何をしているのかを説明するコメントを追加することをお勧めします。ここでDERの仕様をどのようにしているかは、私にはあまり明らかではありません。目立つもの - toUnsignedStringで何をやっていますか?私はなぜ仮数を文字列表現に変換しているのかわからないし、それらのキャラクタを取り、対応するバイトをエンコードしています。 – Kevin

+0

あなたはベース2を使用してエンコードする必要があります。ベース10をやろうとしているかもしれません。私は考えていません。 – Kevin

答えて

1

であるであるべきです使用する文字(BER/D ERはケビンによってコメントとして、いないビット)のみベース= 10のために使用し、また、全く意味をなさないた後方それらをやって、あなたのエラーは、次のとおりです。

  • IEEE-その後、ISO/IEC浮動小数点ほとんどの他のように、Java(および最も普及しているCPU)で使用されているスキームは、BER/DERのような「仮数」(より良い、仮数)の左側に暗黙のバイナリ/基数ポイントを持ち、その暗黙のポイントの左側に1ビットの「隠された」

  • DER(ただしBERはありません)は、仮数部を除外しなければなりません(すでに特殊化されていたゼロを除く)。ベース= 2のためにこれが唯一の指数を調整する必要がありますが、Javaの組み込みBigInteger.toByteArray()は、すでに標準的な生成するので、さらに8または16のスケールファクタを必要とすることができるだけでなく

は、あなたは、整数をエンコードするためにASN1OutputStreamを必要としませんビッグエンディアンの2の補数であり、実際にはIEEE-ISO/IEC値では発生しないため、2オクテットを超える指数の長さを処理する必要はありません。 (あなたがBigDecimal値または類似のを望んでいたなら、彼らが必要とすることができます。)

次のコードが正しいと期待値(タグと長さを除く)生産:

double d = 1398101.25d; 
    ByteArrayOutputStream str = new ByteArrayOutputStream(); 
    // for demo, use real output as needed 

    long bits = Double.doubleToRawLongBits(d); 
    int signByte = (int)(bits>>(63-6))&(1<<6) | (1<<7); 
    // shift to the correct place to start with, and pre-add bit 8 
    int exponent = ((int)(bits>>52)&0x7FF)-(1023+52); 
    // don't need to box/unbox to do arithmetic 
    long mantissa = (bits&0xFFFFFFFFFFFFFL) | (1L<<52); 
    // add the hidden bit 
    while((mantissa&1)==0){ mantissa>>=1; exponent++; } 
    // normalize 
    byte[] exptbytes = BigInteger.valueOf(exponent).toByteArray(); 
    if(exptbytes.length<3) str.write(signByte|(exptbytes.length-1)); 
    else{ str.write(signByte|3); str.write(exptbytes.length); } 
    // only the if branch is actually needed 
    str.write (exptbytes); 
    str.write (BigInteger.valueOf(mantissa/*>>scale*/).toByteArray()); 

    System.out.println(Arrays.toString(str.toByteArray())); 
    // for demo 
+0

ありがとうございました!私はテストに合格しました。そして今、Squeakの暗号ASN1フレームワークのJavaへの移植が完了しました。今ParrotTalkを進めるために、私の2048ビットの鍵はコネクションフレームワークをネゴシエートしました。 –

+0

私はどこかで自分のニュースを共有しなければなりません。 ASN1エンコーダを完成させるのに役立ちました。 –

+0

私はランデブーの作業を終えてから、私の暗号であるivSequenceとmacに夢中になって、それをすべて稼いでいました。私は今、Squeak版、Pharo版、Java版ParrotTalk Protocol [1]を持っています。同じASN.1ベースのRSA公開鍵、暗号とエンコーダの選択、diffie hellmanパラメータとトラフィックの署名のベースのランデブーおよび交換の後に、3つのシステムすべてでデータを暗号化および復号化します。到着したデータのセッションからのMAC移入、復号化、MAC通関確認、復号化、およびイベントブロードキャストを含む暗号化スタックを完成させ、構築する。 –

関連する問題