#include #include #include #include #include #include "base32.h" #include "otppass.h" unsigned char* extract_secret(const char* otpauth_url, size_t* decoded_len) { char *lang = getenv("SP_LANG"); const char* secret_start = strstr(otpauth_url, "secret="); if (!secret_start) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("In the middle of the OTPAuth URL, could not found secret"); else perror("OTPAuth URLの中に、シークレットを見つけられませんでした"); return NULL; } secret_start += 7; const char* secret_end = strchr(secret_start, '&'); if (!secret_end) { if (secret_start[0] != '\0') { secret_end = secret_start + strlen(secret_start); } else { secret_end = secret_start; } } if (secret_end < secret_start) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Illegal secret range"); else perror("不正なシークレットの距離"); return NULL; } size_t secret_len = secret_end - secret_start; char* secret_encoded = (char*)malloc(secret_len + 1); if (secret_encoded == NULL) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to allocating memory"); else perror("メモリの役割に失敗"); return NULL; } strncpy(secret_encoded, secret_start, secret_len); secret_encoded[secret_len] = '\0'; unsigned char* secret_decoded = base32_decode(secret_encoded, decoded_len); free(secret_encoded); if (!secret_decoded) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to decrypting of the BASE32"); else perror("BASE32の復号化に失敗"); return NULL; } return secret_decoded; } uint32_t generate_totp(const char *secret, uint64_t counter) { counter = htobe64(counter); unsigned char hash[SHA_DIGEST_LENGTH]; HMAC(EVP_sha1(), secret, strlen(secret), (unsigned char *)&counter, sizeof(counter), hash, NULL); int offset = hash[SHA_DIGEST_LENGTH - 1] & 0x0F; uint32_t truncated_hash = (hash[offset] & 0x7F) << 24 | (hash[offset + 1] & 0xFF) << 16 | (hash[offset + 2] & 0xFF) << 8 | (hash[offset + 3] & 0xFF); return truncated_hash % 1000000; } void otppass(char* file) { char *lang = getenv("SP_LANG"); gpgme_ctx_t ctx; gpgme_error_t err; gpgme_data_t in, out; size_t secret_len; gpgme_check_version(NULL); err = gpgme_new(&ctx); if (err) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to generating the GPG"); else perror("GPGMEを創作に失敗"); exit(1); } err = gpgme_data_new_from_file(&in, file, 1); if (err) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to reading the GPG file"); else perror("GPGファイルを読込に失敗"); exit(1); } err = gpgme_data_new(&out); if (err) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to reading the GPG data"); else perror("GPGデータを読込に失敗"); exit(1); } err = gpgme_op_decrypt(ctx, in, out); if (err) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to decrypting the GPG"); else perror("GPGを復号化に失敗"); exit(1); } char* secret = gpgme_data_release_and_get_mem(out, &secret_len); if (!secret) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to getting the GPG"); else perror("GPGを受取に失敗"); exit(1); } size_t decoded_len; unsigned char* secret_decoded = extract_secret(secret, &decoded_len); if (!secret_decoded) { if (lang != NULL && strncmp(lang, "en", 2) == 0) perror("Failed to decoding or exporting secret"); else perror("シークレットの抽出又はデコードに失敗しました"); free(secret); exit(1); } time_t current_time = time(NULL); uint64_t counter = current_time / 30; uint32_t otp = generate_totp((const char*)secret_decoded, counter); printf("%06d\n", otp); gpgme_data_release(in); gpgme_release(ctx); free(secret); free(secret_decoded); }