Данные, подписанные на iOS, не могут быть проверены в Java - PullRequest
0 голосов
/ 21 мая 2018

У меня есть некоторые данные, которые я подписываю на iOS с помощью SecKeyRawSign, используя закрытый ключ Elliptic Curve.Однако, проверяя, что данные в Java с использованием Signature.verify() возвращают false

Данные представляют собой случайное 64-разрядное целое число, разбитое на байты, например:

uint64_t nonce = (some 64 bit integer)
NSData *nonceData = [NSData dataWithBytes: &nonce length: sizeof(nonce)];

Из этих данных ясоздаю дайджест SHA256

int digestLength = CC_SHA256_DIGEST_LENGTH;
uint8_t *digest = malloc(digestLength);
CC_SHA256(nonceData.bytes, (CC_LONG)nonceData.length, digest);
NSData *digestData = [NSData dataWithBytes:digest length:digestLength];

и затем подписываю его закрытым ключом

size_t signedBufferSize = kMaxCipherBufferSize;
uint8_t *signedBuffer = malloc(kMaxCipherBufferSize);

OSStatus status = SecKeyRawSign(privateKeyRef,
                                kSecPaddingPKCS1SHA256,
                                (const uint8_t *)digestData.bytes,
                                digestData.length,
                                &signedBuffer[0],
                                &signedBufferSize);

NSData *signedData = nil;
if (status == errSecSuccess) {
    signedData = [NSData dataWithBytes:signedBuffer length:signedBufferSize];
}

Кажется, все работает нормально.

Затем на сервере Java япытаясь проверить подписанные данные

PublicKey publicKey = (a public key sent from iOS, X509 encoded)

Long nonce = (64 bit integer sent from iOS)
String signedNonce = (base64 encoded signed data)

ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(nonce);
byte[] nonceBytes = buffer.array();
byte[] signedNonceBytes = Base64.getDecoder().decode(signedNonce.getBytes());

Signature signer = Signature.getInstance( "SHA256withECDSA" );
signer.initVerify( publicKey );
signer.update( nonceBytes );
Boolean isVerified = signer.verify( signedNonceBytes );

На этом этапе signer.verify() возвращает false

Я также пытался подписать простые данные вместо дайджеста SHA256, но это неработать либо.

Чего мне не хватает?Я правильно подписываю данные?Я использую правильное дополнение?Есть ли что-то еще, что нужно сделать с данными, чтобы иметь возможность проверить это с помощью алгоритма SHA256withECDSA?

Ответы [ 4 ]

0 голосов
/ 01 июня 2018

Порядок следования байтов не совпадает:

  • iOS is little endian .При создании nonceData этот порядок сохраняется.
  • На стороне Java ByteBuffer по умолчанию равен big endian , независимо от базовой операционной системы / оборудования.

Так что вам нужно изменить порядок байтов:

ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putLong(nonce);
0 голосов
/ 30 мая 2018

Я могу посоветовать вам использовать некоторую Crypto Library, которая доступна как для iOS, так и для сторон JAVA (например: https://github.com/VirgilSecurity/virgil-crypto).). Это гарантирует, что алгоритм и типы блоков (и т. Д.) Одинаковы в обоих случаях ивам больше не нужно об этом беспокоиться. Я полагаю, вы найдете множество крипто-библиотек на GitHub.

0 голосов
/ 30 мая 2018

В getBytes () вы можете указать технику кодирования, используя java.nio.charset.StandardCharsets.и сделайте то же самое с декодером.

https://docs.oracle.com/javase/7/docs/api/java/nio/charset/StandardCharsets.html

0 голосов
/ 25 мая 2018

Я - Java-парень, поэтому я не могу ничего сказать о стороне iOS, но быструю проверку Java-стороны можно выполнить, используя прокомментированные предположения:

// Generate a new random EC keypair for testing
KeyPair keys = KeyPairGenerator.getInstance("EC").generateKeyPair();
PrivateKey privateKey = keys.getPrivate();
PublicKey publicKey = keys.getPublic();

// Generate a Random nonce to test with
byte[] nonceBytes = new byte[8]; // (some 64 bit integer)
new Random(System.nanoTime()).nextBytes(nonceBytes);

// sign     
Signature sign = Signature.getInstance("SHA256withECDSA");
sign.initSign(privateKey);
sign.update(nonceBytes);
byte[] signature = sign.sign();

//verify
Signature verify = Signature.getInstance("SHA256withECDSA");
verify.initVerify(publicKey);
verify.update(nonceBytes);
Boolean isVerified = verify.verify(signature);

// print results
System.out.println("nonce used  ::" + Base64.getEncoder().encodeToString(nonceBytes));
System.out.println("Signed nonce ::" + Base64.getEncoder().encodeToString(signature));
System.out.println("nonce used ::" + isVerified);

Как вы 'Ожидая возврата, код выше всегда вернет, что подпись проверена.Проверьте правильность своих предположений и подтвердите правильность используемых ключей на обеих сторонах.

...