Я хочу прочитать закладки и историю из учетных записей Firefox Sync в одном из моих приложений для iOS, и у меня это работает для всех «новых» учетных записей (с адресом электронной почты в качестве имени для входа), но это не работает для старых учетных записей (тех, где пользователь все еще может создать свое собственное имя для входа). И я не уверен, в чем проблема. У меня было много трудностей, чтобы найти все соответствующие детали в документации по Firefox Sync API, мне часто приходилось искать информацию в других местах, поэтому я предполагаю, что мне все еще не хватает важной информации.
Я делаю следующее:
У меня есть логин, пароль и ключ синхронизации. Первым шагом является получение «узла переплетения», сервера, на котором хранятся данные пользователей. Мы получаем эту информацию от
https://auth.services.mozilla.com/user/1.0/[loginname]/node/weave"
и использование имени пользователя и пароля для базовой аутентификации для этого запроса. Первая проблема заключалась в том, что «[имя пользователя]» никогда не принималось. Я обнаружил, что когда логин является адресом электронной почты, он должен быть в кодировке SHA1 и base32. Я не нашел эту информацию в документации API, я нашел ее в блоге в другом месте. Для более старых учетных записей, где имя пользователя не является адресом электронной почты, кажется, что оно не должно кодироваться через SHA1 и base32.
Итак, мой первый вопрос: когда именно необходима кодировка SHA1-base32? Только в том случае, если имя для входа является адресом электронной почты или когда имя для входа в старом стиле содержит определенные символы (в том случае, если вообще можно использовать какие-либо специальные символы)?
Этот первый шаг работает хорошо. Я получаю "узел переплетения" для старых и новых учетных записей просто отлично, так
логин и пароль приняты и, кажется, закодированы правильно (по крайней мере, в моих тестовых примерах
с SHA1 / base32 для новых учетных записей и «необработанными» данными для старых учетных записей).
Следующим шагом будет получение ключей для расшифровки данных закладок. Я получаю эти данные от
https://[Weave node]/1.1/[login name]/storage/crypto/keys
снова с базовой аутентификацией.
Я прекрасно получаю ответ JSON, который включает в себя «зашифрованный текст», «iv» и «hmac», из которого я должен иметь возможность создавать ключи AES для расшифровки данных.
Но расшифровка ключей работает только для новых учетных записей (логин является адресом электронной почты) и не работает для старых учетных записей. И это мой второй вопрос: что мне нужно сделать, чтобы надежно получить ключи для всех учетных записей?
AFAIK, что я должен был сделать, это использовать ключ синхронизации и логин и создать ключ шифрования, который можно использовать для дешифрования зашифрованного текста сверху. Так что это будет в псевдокоде
выглядеть так:
encryptionkey = HMAC-SHA256(sync_key, "Sync-AES_256_CBC-HMAC256" + loginname + "\x01")
Где ключ синхронизации - это декодированное значение base32 из строки, введенной пользователем
а имя входа - это либо необработанное имя входа (старые учетные записи), либо строка в кодировке SHA1 / Base32 из имени входа (новые учетные записи).
И для расшифровки "зашифрованного текста" я делаю это (Задача C):
NSString *decryptedPayload = nil;
NSData *encryptionkey = ... // See above, just encapsuled as NSData object.
NSData *cipherdata = [cyphertext base64DecodedData];
NSData *ivdata = [iv base64DecodedData];
size_t bufferSize = ([cipherdata length] + kCCBlockSizeAES128);
void *buffer = calloc(bufferSize, sizeof(uint8_t));
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[encryptionkey bytes], [encryptionkey length],
[ivdata bytes],
[cipherdata bytes], [cipherdata length],
buffer, bufferSize, &numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
NSData *decryptedData = [NSData dataWithBytes:buffer length:numBytesDecrypted];
decryptedPayload = [NSString stringWithData:resData];
}
free(buffer);
Теперь «decryptedPayload» содержит расшифрованную информацию о ключах AES. Это отлично работает для новых учетных записей, но расшифровка не удаётся для старых учетных записей (CCCrypt возвращает kCCDecodeError). Что мне не хватает? Что я делаю не так?