Compare commits
13 Commits
0.13
...
781e775b3b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
781e775b3b | ||
|
|
55a139db82 | ||
|
|
b291bb430b | ||
|
|
a9353b3af3 | ||
|
|
7706b73d8c | ||
| 252c44a155 | |||
|
|
a7743fa18c | ||
| 4853426d6c | |||
| de2216f259 | |||
|
|
b19bc5ffa3 | ||
|
|
517975ef93 | ||
|
|
ca2a932485 | ||
|
|
171594a92d |
@@ -1,3 +1,7 @@
|
||||
2017-06-22 Peter van Dijk <peter.van.dijk@powerdns.com>, Kees Monshouwer <mind04@monshouwer.eu>
|
||||
|
||||
* Fix leading zero(s) padding in ECDSA sig conversion
|
||||
|
||||
2017-01-06 David Blacka <davidb@verisign.com>
|
||||
|
||||
* Released version 0.13
|
||||
|
||||
@@ -46,7 +46,10 @@
|
||||
classpathref="project.classpath"
|
||||
deprecation="true"
|
||||
includeantruntime="false"
|
||||
includes="com/verisignlabs/dnssec/" />
|
||||
includes="com/verisignlabs/dnssec/"
|
||||
debug="true"
|
||||
source="1.7"
|
||||
target="1.7" />
|
||||
</target>
|
||||
|
||||
<target name="sectools-jar" depends="usage,sectools">
|
||||
|
||||
BIN
lib/eddsa-0.3.0.jar
Normal file
BIN
lib/eddsa-0.3.0.jar
Normal file
Binary file not shown.
@@ -247,6 +247,19 @@ public abstract class CLBase
|
||||
}
|
||||
}
|
||||
|
||||
public static long parseLong(String s, long def)
|
||||
{
|
||||
try
|
||||
{
|
||||
long v = Long.parseLong(s);
|
||||
return v;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a date/time from a command line time/offset duration string.
|
||||
*
|
||||
@@ -272,6 +285,11 @@ public abstract class CLBase
|
||||
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
|
||||
return new Date(start.getTime() + offset);
|
||||
}
|
||||
if (duration.length() <= 10)
|
||||
{
|
||||
long epoch = parseLong(duration, 0) * 1000;
|
||||
return new Date(epoch);
|
||||
}
|
||||
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
@@ -61,6 +61,7 @@ public class SignRRset extends CLBase
|
||||
public String inputfile = null;
|
||||
public String outputfile = null;
|
||||
public boolean verifySigs = false;
|
||||
public boolean verboseSigning = false;
|
||||
|
||||
public CLIState()
|
||||
{
|
||||
@@ -74,6 +75,7 @@ public class SignRRset extends CLBase
|
||||
{
|
||||
// boolean options
|
||||
opts.addOption("a", "verify", false, "verify generated signatures>");
|
||||
opts.addOption("V", "verbose-signing", false, "Display verbose signing activity.");
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withArgName("dir");
|
||||
@@ -104,6 +106,7 @@ public class SignRRset extends CLBase
|
||||
String optstr = null;
|
||||
|
||||
if (cli.hasOption('a')) verifySigs = true;
|
||||
if (cli.hasOption('V')) verboseSigning = true;
|
||||
|
||||
if ((optstr = cli.getOptionValue('D')) != null)
|
||||
{
|
||||
@@ -310,7 +313,7 @@ public class SignRRset extends CLBase
|
||||
state.outputfile = state.inputfile + ".signed";
|
||||
}
|
||||
|
||||
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
||||
JCEDnsSecSigner signer = new JCEDnsSecSigner(state.verboseSigning);
|
||||
|
||||
List<RRSIGRecord> sigs = signer.signRRset(rrset, keypairs, state.start, state.expire);
|
||||
for (RRSIGRecord s : sigs)
|
||||
|
||||
@@ -147,13 +147,13 @@ public class VerifyZone extends CLBase
|
||||
if (errors > 0)
|
||||
{
|
||||
System.out.println("zone did not verify.");
|
||||
System.exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("zone verified.");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
|
||||
@@ -39,6 +39,11 @@ import java.util.logging.Logger;
|
||||
|
||||
import org.xbill.DNS.DNSSEC;
|
||||
|
||||
// for now, we need to import the EdDSA parameter spec classes
|
||||
// because they have no generic form in java.security.spec.*
|
||||
// sadly, this will currently fail if you don't have the lib.
|
||||
import net.i2p.crypto.eddsa.spec.*;
|
||||
|
||||
/**
|
||||
* This class handles translating DNS signing algorithm identifiers into various
|
||||
* usable java implementations.
|
||||
@@ -64,6 +69,7 @@ public class DnsKeyAlgorithm
|
||||
public static final int DSA = 3;
|
||||
public static final int ECC_GOST = 4;
|
||||
public static final int ECDSA = 5;
|
||||
public static final int EDDSA = 6;
|
||||
|
||||
private static class AlgEntry
|
||||
{
|
||||
@@ -90,6 +96,17 @@ public class DnsKeyAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
private static class EdAlgEntry extends AlgEntry
|
||||
{
|
||||
public EdDSAParameterSpec ed_spec;
|
||||
|
||||
public EdAlgEntry(int algorithm, String sigName, int baseType, EdDSAParameterSpec spec)
|
||||
{
|
||||
super(algorithm, sigName, baseType);
|
||||
this.ed_spec = spec;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a mapping of algorithm identifier to Entry. The Entry contains the
|
||||
* data needed to map the algorithm to the various crypto implementations.
|
||||
@@ -113,6 +130,8 @@ public class DnsKeyAlgorithm
|
||||
private KeyPairGenerator mECGOSTKeyGenerator;
|
||||
/** This is a cached key pair generator for ECDSA_P256 keys. */
|
||||
private KeyPairGenerator mECKeyGenerator;
|
||||
/** This is a cached key pair generator for EdDSA keys. */
|
||||
private KeyPairGenerator mEdKeyGenerator;
|
||||
|
||||
private Logger log = Logger.getLogger(this.getClass().toString());
|
||||
|
||||
@@ -132,6 +151,17 @@ public class DnsKeyAlgorithm
|
||||
}
|
||||
catch (ReflectiveOperationException e) { }
|
||||
|
||||
// Attempt to add the EdDSA-Java provider.
|
||||
try
|
||||
{
|
||||
Class<?> eddsa_provider_class = Class.forName("net.i2p.crypto.eddsa.EdDSASecurityProvider");
|
||||
Provider eddsa_provider = (Provider) eddsa_provider_class.newInstance();
|
||||
Security.addProvider(eddsa_provider);
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
log.warning("Unable to load EdDSA provider");
|
||||
}
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -184,6 +214,13 @@ public class DnsKeyAlgorithm
|
||||
addAlgorithm(DNSSEC.Algorithm.ECDSAP384SHA384, "SHA384withECDSA", ECDSA, "secp384r1");
|
||||
addMnemonic("ECDSAP384SHA384", DNSSEC.Algorithm.ECDSAP384SHA384);
|
||||
addMnemonic("ECDSA-P384", DNSSEC.Algorithm.ECDSAP384SHA384);
|
||||
|
||||
// EdDSA is not supported by either the Java 1.8 Sun crypto
|
||||
// provider or bouncycastle. It is added by the Ed25519-Java
|
||||
// library.
|
||||
// FIXME: add constant for the EdDSA algs to DNSJava.
|
||||
addAlgorithm(15, "NONEwithEdDSA", EDDSA, "Ed25519");
|
||||
addMnemonic("ED25519", 15);
|
||||
}
|
||||
|
||||
private void addAlgorithm(int algorithm, String sigName, int baseType)
|
||||
@@ -193,19 +230,44 @@ public class DnsKeyAlgorithm
|
||||
|
||||
private void addAlgorithm(int algorithm, String sigName, int baseType, String curveName)
|
||||
{
|
||||
ECParameterSpec ec_spec = ECSpecFromAlgorithm(algorithm);
|
||||
if (ec_spec == null) ec_spec = ECSpecFromName(curveName);
|
||||
if (ec_spec == null) return;
|
||||
// Check to see if we can get a Signature object for this algorithm.
|
||||
try {
|
||||
Signature.getInstance(sigName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// If not, do not add the algorithm.
|
||||
return;
|
||||
if (baseType == ECDSA)
|
||||
{
|
||||
ECParameterSpec ec_spec = ECSpecFromAlgorithm(algorithm);
|
||||
if (ec_spec == null) ec_spec = ECSpecFromName(curveName);
|
||||
if (ec_spec == null) return;
|
||||
|
||||
// Check to see if we can get a Signature object for this algorithm.
|
||||
try {
|
||||
Signature.getInstance(sigName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// for now, let's find out
|
||||
log.severe("could not get signature for " + sigName + ": " + e.getMessage());
|
||||
// If not, do not add the algorithm.
|
||||
return;
|
||||
}
|
||||
ECAlgEntry entry = new ECAlgEntry(algorithm, sigName, baseType, ec_spec);
|
||||
mAlgorithmMap.put(algorithm, entry);
|
||||
}
|
||||
else if (baseType == EDDSA)
|
||||
{
|
||||
EdDSAParameterSpec ed_spec = EdDSASpecFromAlgorithm(algorithm);
|
||||
if (ed_spec == null) ed_spec = EdDSASpecFromName(curveName);
|
||||
if (ed_spec == null) return;
|
||||
|
||||
// Check to see if we can get a Signature object for this algorithm.
|
||||
try {
|
||||
Signature.getInstance(sigName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// for now, let's find out
|
||||
log.severe("could not get signature for " + sigName + ": " + e.getMessage());
|
||||
// If not, do not add the algorithm.
|
||||
return;
|
||||
}
|
||||
EdAlgEntry entry = new EdAlgEntry(algorithm, sigName, baseType, ed_spec);
|
||||
mAlgorithmMap.put(algorithm, entry);
|
||||
}
|
||||
|
||||
ECAlgEntry entry = new ECAlgEntry(algorithm, sigName, baseType, ec_spec);
|
||||
mAlgorithmMap.put(algorithm, entry);
|
||||
|
||||
}
|
||||
|
||||
private void addMnemonic(String m, int alg)
|
||||
@@ -230,7 +292,7 @@ public class DnsKeyAlgorithm
|
||||
|
||||
if (!mAlgorithmMap.containsKey(original_algorithm))
|
||||
{
|
||||
log.warning("Unable to alias algorith " + alias
|
||||
log.warning("Unable to alias algorithm " + alias
|
||||
+ " to unknown algorithm identifier " + original_algorithm);
|
||||
return;
|
||||
}
|
||||
@@ -292,6 +354,31 @@ public class DnsKeyAlgorithm
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// For curves where we don't (or can't) get the parameters from a standard
|
||||
// name, we can construct the parameters here.
|
||||
private EdDSAParameterSpec EdDSASpecFromAlgorithm(int algorithm)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private EdDSAParameterSpec EdDSASpecFromName(String stdName)
|
||||
{
|
||||
try
|
||||
{
|
||||
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(stdName);
|
||||
if (spec != null) return spec;
|
||||
throw new InvalidParameterSpecException("Edwards Curve " + stdName + " not found.");
|
||||
}
|
||||
// catch (NoSuchAlgorithmException e) {
|
||||
// log.info("Edwards Curve not supported by any crypto provider: " + e.getMessage());
|
||||
// }
|
||||
catch (InvalidParameterSpecException e) {
|
||||
log.info("Edwards Curve " + stdName + " not supported");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] supportedAlgMnemonics()
|
||||
{
|
||||
Set<Integer> keyset = mAlgorithmMap.keySet();
|
||||
@@ -350,6 +437,16 @@ public class DnsKeyAlgorithm
|
||||
return ec_entry.ec_spec;
|
||||
}
|
||||
|
||||
public EdDSAParameterSpec getEdwardsCurveParams(int algorithm)
|
||||
{
|
||||
AlgEntry entry = getEntry(algorithm);
|
||||
if (entry == null) return null;
|
||||
if (!(entry instanceof EdAlgEntry)) return null;
|
||||
EdAlgEntry ed_entry = (EdAlgEntry) entry;
|
||||
|
||||
return ed_entry.ed_spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a possible algorithm alias back to the original DNSSEC algorithm
|
||||
* number
|
||||
@@ -507,8 +604,29 @@ public class DnsKeyAlgorithm
|
||||
pair = mECKeyGenerator.generateKeyPair();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NoSuchAlgorithmException("Alg " + algorithm);
|
||||
case EDDSA:
|
||||
{
|
||||
if (mEdKeyGenerator == null)
|
||||
{
|
||||
mEdKeyGenerator = KeyPairGenerator.getInstance("EdDSA");
|
||||
}
|
||||
|
||||
EdDSAParameterSpec ed_spec = getEdwardsCurveParams(algorithm);
|
||||
try
|
||||
{
|
||||
mEdKeyGenerator.initialize(ed_spec, new SecureRandom());
|
||||
}
|
||||
catch (InvalidAlgorithmParameterException e)
|
||||
{
|
||||
// Fold the InvalidAlgorithmParameterException into our existing
|
||||
// thrown exception. Ugly, but requires less code change.
|
||||
throw new NoSuchAlgorithmException("invalid key parameter spec");
|
||||
}
|
||||
pair = mEdKeyGenerator.generateKeyPair();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NoSuchAlgorithmException("Alg " + algorithm);
|
||||
}
|
||||
|
||||
return pair;
|
||||
|
||||
@@ -36,6 +36,11 @@ import javax.crypto.interfaces.DHPublicKey;
|
||||
import javax.crypto.spec.DHParameterSpec;
|
||||
import javax.crypto.spec.DHPrivateKeySpec;
|
||||
|
||||
// For now, just import the native EdDSA classes
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||
import net.i2p.crypto.eddsa.spec.*;
|
||||
|
||||
import org.xbill.DNS.DNSKEYRecord;
|
||||
import org.xbill.DNS.DNSSEC;
|
||||
import org.xbill.DNS.DNSSEC.DNSSECException;
|
||||
@@ -56,6 +61,7 @@ public class DnsKeyConverter
|
||||
private KeyFactory mDSAKeyFactory;
|
||||
private KeyFactory mDHKeyFactory;
|
||||
private KeyFactory mECKeyFactory;
|
||||
private KeyFactory mEdKeyFactory;
|
||||
private DnsKeyAlgorithm mAlgorithms;
|
||||
|
||||
public DnsKeyConverter()
|
||||
@@ -89,8 +95,20 @@ public class DnsKeyConverter
|
||||
pKeyRecord.getKey());
|
||||
}
|
||||
|
||||
// do not rely on DNSJava's method for EdDSA for now.
|
||||
if (mAlgorithms.baseType(originalAlgorithm) == DnsKeyAlgorithm.EDDSA)
|
||||
{
|
||||
try {
|
||||
return parseEdDSADNSKEYRecord(pKeyRecord);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
// just to be expedient, recast this as a NoSuchAlgorithmException.
|
||||
throw new NoSuchAlgorithmException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// This uses DNSJava's DNSSEC.toPublicKey() method.
|
||||
return pKeyRecord.getPublicKey();
|
||||
}
|
||||
catch (DNSSECException e)
|
||||
@@ -99,6 +117,20 @@ public class DnsKeyConverter
|
||||
}
|
||||
}
|
||||
|
||||
/** Since we don't (yet) have support in DNSJava for parsing the
|
||||
newer EdDSA algorithms, here is a local version. */
|
||||
private PublicKey parseEdDSADNSKEYRecord(DNSKEYRecord pKeyRecord)
|
||||
throws IllegalArgumentException, NoSuchAlgorithmException, InvalidKeySpecException
|
||||
{
|
||||
byte[] seed = pKeyRecord.getKey();
|
||||
|
||||
EdDSAPublicKeySpec spec = new EdDSAPublicKeySpec
|
||||
(seed, mAlgorithms.getEdwardsCurveParams(pKeyRecord.getAlgorithm()));
|
||||
|
||||
KeyFactory factory = KeyFactory.getInstance("EdDSA");
|
||||
return factory.generatePublic(spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a JCA public key and the ancillary data, generate a DNSKEY record.
|
||||
*/
|
||||
@@ -107,6 +139,9 @@ public class DnsKeyConverter
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mAlgorithms.baseType(alg) == DnsKeyAlgorithm.EDDSA) {
|
||||
return generateEdDSADNSKEYRecord(name, dclass, ttl, flags, alg, key);
|
||||
}
|
||||
return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg,
|
||||
key);
|
||||
}
|
||||
@@ -117,6 +152,15 @@ public class DnsKeyConverter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DNSKEYRecord generateEdDSADNSKEYRecord(Name name, int dclass, long ttl,
|
||||
int flags, int alg, PublicKey key)
|
||||
{
|
||||
EdDSAPublicKey ed_key = (EdDSAPublicKey) key;
|
||||
byte[] key_data = ed_key.getAbyte();
|
||||
return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg,
|
||||
key_data);
|
||||
}
|
||||
// Private Key Specific Parsing routines
|
||||
|
||||
/**
|
||||
@@ -204,6 +248,8 @@ public class DnsKeyConverter
|
||||
return parsePrivateECDSA(lines, alg);
|
||||
case DnsKeyAlgorithm.ECDSA:
|
||||
return parsePrivateECDSA(lines, alg);
|
||||
case DnsKeyAlgorithm.EDDSA:
|
||||
return parsePrivateEdDSA(lines, alg);
|
||||
default:
|
||||
throw new IOException("unsupported private key algorithm: " + val);
|
||||
}
|
||||
@@ -487,6 +533,60 @@ public class DnsKeyConverter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the remaining lines in a BIND9-style ECDSA private key, parse the key
|
||||
* info and translate it into a JCA private key object.
|
||||
* @param lines The remaining lines in a private key file (after
|
||||
* @throws NoSuchAlgorithmException
|
||||
* If elliptic curve is not available.
|
||||
*/
|
||||
private PrivateKey parsePrivateEdDSA(StringTokenizer lines, int algorithm)
|
||||
throws NoSuchAlgorithmException
|
||||
{
|
||||
byte[] seed = null;
|
||||
|
||||
while (lines.hasMoreTokens())
|
||||
{
|
||||
String line = lines.nextToken();
|
||||
if (line == null) continue;
|
||||
|
||||
if (line.startsWith("#")) continue;
|
||||
|
||||
String val = value(line);
|
||||
if (val == null) continue;
|
||||
|
||||
byte[] data = base64.fromString(val);
|
||||
|
||||
if (line.startsWith("PrivateKey: "))
|
||||
{
|
||||
seed = data;
|
||||
}
|
||||
}
|
||||
|
||||
if (mEdKeyFactory == null)
|
||||
{
|
||||
mEdKeyFactory = KeyFactory.getInstance("EdDSA");
|
||||
}
|
||||
EdDSAParameterSpec ed_spec = mAlgorithms.getEdwardsCurveParams(algorithm);
|
||||
if (ed_spec == null)
|
||||
{
|
||||
throw new NoSuchAlgorithmException("DNSSEC algorithm " + algorithm +
|
||||
" is not a recognized Edwards Curve algorithm");
|
||||
}
|
||||
|
||||
KeySpec spec = new EdDSAPrivateKeySpec(seed, ed_spec);
|
||||
|
||||
try
|
||||
{
|
||||
return mEdKeyFactory.generatePrivate(spec);
|
||||
}
|
||||
catch (InvalidKeySpecException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a private key and public key, generate the BIND9 style private key
|
||||
* format.
|
||||
@@ -509,6 +609,11 @@ public class DnsKeyConverter
|
||||
{
|
||||
return generatePrivateEC((ECPrivateKey) priv, (ECPublicKey) pub, alg);
|
||||
}
|
||||
else if (priv instanceof EdDSAPrivateKey && pub instanceof EdDSAPublicKey)
|
||||
{
|
||||
return generatePrivateED((EdDSAPrivateKey) priv, (EdDSAPublicKey) pub, alg);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -630,4 +735,22 @@ public class DnsKeyConverter
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an edwards curve key pair, and the actual algorithm (which will
|
||||
* describe the curve used), return the BIND9-style text encoding.
|
||||
*/
|
||||
private String generatePrivateED(EdDSAPrivateKey priv, EdDSAPublicKey pub, int alg)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter out = new PrintWriter(sw);
|
||||
|
||||
out.println("Private-key-format: v1.2");
|
||||
out.println("Algorithm: " + alg + " (" + mAlgorithms.algToString(alg)
|
||||
+ ")");
|
||||
out.print("PrivateKey: ");
|
||||
out.println(base64.toString(priv.getSeed()));
|
||||
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -526,10 +526,19 @@ public class SignUtils
|
||||
s_src_pos = (byte) (r_src_pos + r_src_len); s_pad = 0;
|
||||
len = (byte) (6 + r_src_len + s_src_len);
|
||||
|
||||
if (signature[r_src_pos] < 0) {
|
||||
r_pad = 1; len++;
|
||||
// leading zeroes are forbidden
|
||||
while (signature[r_src_pos] == 0 && r_src_len > 0) {
|
||||
r_src_pos++; r_src_len--; len--;
|
||||
}
|
||||
if (signature[s_src_pos] < 0) {
|
||||
while (signature[s_src_pos] == 0 && s_src_len > 0) {
|
||||
s_src_pos++; s_src_len--; len--;
|
||||
}
|
||||
|
||||
// except when they are mandatory
|
||||
if (r_src_len > 0 && signature[r_src_pos] < 0) {
|
||||
r_pad = 1; len++;
|
||||
}
|
||||
if (s_src_len > 0 && signature[s_src_pos] < 0) {
|
||||
s_pad = 1; len++;
|
||||
}
|
||||
byte[] sig = new byte[len];
|
||||
|
||||
Reference in New Issue
Block a user