Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encoding/decoding negative integers and bigger integers #90

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/asn1/decoders/der.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ DERNode.prototype._decodeInt = function decodeInt(buffer, values) {
const raw = buffer.raw();
let res = new bignum(raw);

// check if number is negative
if ((raw[0] & 0x80) > 0) {
res = res.fromTwos(raw.length * 8);
}

if (values)
res = values[res.toString(10)] || res;

Expand Down
28 changes: 25 additions & 3 deletions lib/asn1/encoders/der.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const Buffer = require('buffer').Buffer;

const asn1 = require('../../asn1');
const base = asn1.base;
const bignum = asn1.bignum;

// Import DER constants
const der = asn1.constants.der;
Expand Down Expand Up @@ -197,10 +198,25 @@ DERNode.prototype._encodeInt = function encodeInt(num, values) {

// Bignum, assume big endian
if (typeof num !== 'number' && !Buffer.isBuffer(num)) {
const numArray = num.toArray();
if (!num.sign && numArray[0] & 0x80) {
numArray.unshift(0);
let numArray;
if (num.isNeg()) {
const bitLength = num.bitLength();
let width = Math.ceil(bitLength / 8) * 8;
// check if sign bit is occupied
if ((bitLength % 8) === 0) {
// when number is of form 10..0 no correction is needed
if (num.zeroBits() + 1 !== num.bitLength()) {
width += 8;
}
}
numArray = num.toTwos(width).toArray();
} else {
numArray = num.toArray();
if (numArray[0] & 0x80) {
numArray.unshift(0);
}
}

num = new Buffer(numArray);
}

Expand All @@ -216,6 +232,12 @@ DERNode.prototype._encodeInt = function encodeInt(num, values) {
return this._createEncoderBuffer(out);
}

if (num < 0)
return this._encodeInt(new bignum(num));

if (num > 0x7FFFFFFF)
return this._encodeInt(new bignum(num));

if (num < 0x80)
return this._createEncoderBuffer(num);

Expand Down
17 changes: 17 additions & 0 deletions test/der-decode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

const assert = require('assert');
const asn1 = require('..');
const bignum = asn1.bignum;

const Buffer = require('buffer').Buffer;

Expand Down Expand Up @@ -54,6 +55,22 @@ describe('asn1.js DER decoder', function() {
});
}

it('should decode integers', function() {
const Int = asn1.define('Int', function () { this.int(); });
const values = [
['020101', 1],
['0203008011', 0x8011],
['02020080', 128],
['0201FF', -1],
['020180', -128],
['0202FF7F', -129]
];
values.forEach( function (v) {
const decoded = Int.decode(new Buffer(v[0], 'hex'), 'der');
assert(decoded.eq(new bignum(v[1])), v[1]);
});
});

test('should decode choice', function() {
this.choice({
apple: this.bool(),
Expand Down
26 changes: 26 additions & 0 deletions test/der-encode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@ describe('asn1.js DER encoder', function() {
this.int();
}, 0x8011, '0203008011');

test('should encode int -1 properly', function() {
this.int();
}, -1, '0201FF');

test('should encode int -128 properly', function() {
this.int();
}, -128, '020180');

test('should encode int -129 properly', function() {
this.int();
}, -129, '0202FF7F');

test('should encode int 2147483647 properly', function() {
this.int();
}, 2147483647, '02047FFFFFFF');

test('should encode int 2147483648 properly', function() {
this.int();
}, 2147483648, '02050080000000');

test('should encode int 5000000000 properly', function() {
this.int();
}, 5000000000, '0205012A05F200');



test('should omit default value in DER', function() {
this.seq().obj(
this.key('required').def(false).bool(),
Expand Down