diff --git a/CryptoLib/src/Asn1/ClpAsn1Objects.pas b/CryptoLib/src/Asn1/ClpAsn1Objects.pas
index 5f3f8c01..36a2c323 100644
--- a/CryptoLib/src/Asn1/ClpAsn1Objects.pas
+++ b/CryptoLib/src/Asn1/ClpAsn1Objects.pas
@@ -2578,8 +2578,12 @@ Meta = class sealed(TAsn1UniversalType, IAsn1UniversalType)
///
function GetValue(): TBigInteger;
///
- /// Get the positive BigInteger value.
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ /// NB: The BigInteger constructor tolerates any redundant sign bytes (per 'AllowUnsafeInteger').
+ ///
function GetPositiveValue(): TBigInteger;
///
/// Check if this integer has a specific Int32 value.
@@ -2598,26 +2602,50 @@ Meta = class sealed(TAsn1UniversalType, IAsn1UniversalType)
///
function GetIntValueExact(): Int32;
///
- /// Get positive Int32 value, throwing if out of range.
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
function GetIntPositiveValueExact(): Int32;
///
/// Get Int64 value, throwing if out of range.
///
function GetLongValueExact(): Int64;
///
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
+ ///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
+ function GetLongPositiveValueExact(): Int64;
+ ///
/// Try to get Int32 value, returning false if out of range.
///
function TryGetIntValueExact(out AValue: Int32): Boolean;
///
- /// Try to get positive Int32 value, returning false if out of range.
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
function TryGetIntPositiveValueExact(out AValue: Int32): Boolean;
///
/// Try to get Int64 value, returning false if out of range.
///
function TryGetLongValueExact(out AValue: Int64): Boolean;
///
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
+ ///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
+ function TryGetLongPositiveValueExact(out AValue: Int64): Boolean;
+ ///
+ /// Whether the first significant encoding byte has the sign bit set.
+ ///
+ function GetIsNegative(): Boolean;
+ ///
/// Check if bytes are malformed (invalid INTEGER encoding).
///
class function IsMalformed(const ABytes: TCryptoLibByteArray): Boolean; static;
@@ -2642,6 +2670,8 @@ Meta = class sealed(TAsn1UniversalType, IAsn1UniversalType)
property IntValueExact: Int32 read GetIntValueExact;
property IntPositiveValueExact: Int32 read GetIntPositiveValueExact;
property LongValueExact: Int64 read GetLongValueExact;
+ property LongPositiveValueExact: Int64 read GetLongPositiveValueExact;
+ property IsNegative: Boolean read GetIsNegative;
end;
///
@@ -12659,33 +12689,27 @@ function TDerInteger.HasValue(const AX: TBigInteger): Boolean;
end;
function TDerInteger.GetIntValueExact(): Int32;
-var
- LCount: Int32;
begin
- LCount := System.Length(FBytes) - FStart;
- if LCount > 4 then
+ if not TryGetIntValueExact(Result) then
raise EArithmeticCryptoLibException.Create('ASN.1 Integer out of int range');
- Result := TDerInteger.IntValue(FBytes, FStart, SignExtSigned);
end;
function TDerInteger.GetIntPositiveValueExact(): Int32;
-var
- LCount: Int32;
begin
- LCount := System.Length(FBytes) - FStart;
- if (LCount > 4) or ((LCount = 4) and ((FBytes[FStart] and $80) <> 0)) then
+ if not TryGetIntPositiveValueExact(Result) then
raise EArithmeticCryptoLibException.Create('ASN.1 Integer out of positive int range');
- Result := TDerInteger.IntValue(FBytes, FStart, SignExtUnsigned);
end;
function TDerInteger.GetLongValueExact(): Int64;
-var
- LCount: Int32;
begin
- LCount := System.Length(FBytes) - FStart;
- if LCount > 8 then
+ if not TryGetLongValueExact(Result) then
raise EArithmeticCryptoLibException.Create('ASN.1 Integer out of long range');
- Result := TDerInteger.LongValue(FBytes, FStart, SignExtSigned);
+end;
+
+function TDerInteger.GetLongPositiveValueExact(): Int64;
+begin
+ if not TryGetLongPositiveValueExact(Result) then
+ raise EArithmeticCryptoLibException.Create('ASN.1 Integer out of positive long range');
end;
function TDerInteger.TryGetIntValueExact(out AValue: Int32): Boolean;
@@ -12708,7 +12732,7 @@ function TDerInteger.TryGetIntPositiveValueExact(out AValue: Int32): Boolean;
LCount: Int32;
begin
LCount := System.Length(FBytes) - FStart;
- if (LCount > 4) or ((LCount = 4) and ((FBytes[FStart] and $80) <> 0)) then
+ if (LCount > 4) or ((LCount = 4) and IsNegative) then
begin
AValue := 0;
Result := False;
@@ -12718,6 +12742,21 @@ function TDerInteger.TryGetIntPositiveValueExact(out AValue: Int32): Boolean;
Result := True;
end;
+function TDerInteger.TryGetLongPositiveValueExact(out AValue: Int64): Boolean;
+var
+ LCount: Int32;
+begin
+ LCount := System.Length(FBytes) - FStart;
+ if (LCount > 8) or ((LCount = 8) and IsNegative) then
+ begin
+ AValue := 0;
+ Result := False;
+ Exit;
+ end;
+ AValue := TDerInteger.LongValue(FBytes, FStart, SignExtSigned);
+ Result := True;
+end;
+
function TDerInteger.TryGetLongValueExact(out AValue: Int64): Boolean;
var
LCount: Int32;
@@ -12733,6 +12772,11 @@ function TDerInteger.TryGetLongValueExact(out AValue: Int64): Boolean;
Result := True;
end;
+function TDerInteger.GetIsNegative(): Boolean;
+begin
+ Result := (FBytes[FStart] and $80) <> 0;
+end;
+
function TDerInteger.GetEncoding(AEncoding: Int32): IAsn1Encoding;
begin
Result := TPrimitiveEncoding.Create(TAsn1Tags.Universal, TAsn1Tags.Integer, FBytes);
diff --git a/CryptoLib/src/Interfaces/Asn1/ClpIAsn1Objects.pas b/CryptoLib/src/Interfaces/Asn1/ClpIAsn1Objects.pas
index 206a455f..e3fa1eda 100644
--- a/CryptoLib/src/Interfaces/Asn1/ClpIAsn1Objects.pas
+++ b/CryptoLib/src/Interfaces/Asn1/ClpIAsn1Objects.pas
@@ -506,8 +506,12 @@ interface
///
function GetValue(): TBigInteger;
///
- /// Get the positive BigInteger value.
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ /// NB: The BigInteger constructor tolerates any redundant sign bytes (per 'AllowUnsafeInteger').
+ ///
function GetPositiveValue(): TBigInteger;
///
/// Check if this integer has a specific Int32 value.
@@ -526,31 +530,57 @@ interface
///
function GetIntValueExact(): Int32;
///
- /// Get positive Int32 value, throwing if out of range.
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
function GetIntPositiveValueExact(): Int32;
///
/// Get Int64 value, throwing if out of range.
///
function GetLongValueExact(): Int64;
///
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
+ ///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
+ function GetLongPositiveValueExact(): Int64;
+ ///
/// Try to get Int32 value, returning false if out of range.
///
function TryGetIntValueExact(out AValue: Int32): Boolean;
///
- /// Try to get positive Int32 value, returning false if out of range.
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
function TryGetIntPositiveValueExact(out AValue: Int32): Boolean;
///
/// Try to get Int64 value, returning false if out of range.
///
function TryGetLongValueExact(out AValue: Int64): Boolean;
+ ///
+ /// Force the ASN.1 INTEGER encoding to be interpreted as unsigned.
+ ///
+ ///
+ /// In some cases positive values get crammed into a space that's not quite big enough...
+ ///
+ function TryGetLongPositiveValueExact(out AValue: Int64): Boolean;
+ ///
+ /// Whether the first significant encoding byte has the sign bit set.
+ ///
+ function GetIsNegative(): Boolean;
property Bytes: TCryptoLibByteArray read GetBytes;
property Value: TBigInteger read GetValue;
property PositiveValue: TBigInteger read GetPositiveValue;
property IntValueExact: Int32 read GetIntValueExact;
property IntPositiveValueExact: Int32 read GetIntPositiveValueExact;
property LongValueExact: Int64 read GetLongValueExact;
+ property LongPositiveValueExact: Int64 read GetLongPositiveValueExact;
+ property IsNegative: Boolean read GetIsNegative;
end;
///