{"id":410002,"date":"2024-06-29T21:06:37","date_gmt":"2024-06-29T21:06:37","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=410002"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=410002","title":{"rendered":"<span>Building an Arduino based RFID Emulator<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><a href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/570114\/\"><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/3l\/0d\/sg\/3l0dsgfav4dq7jpvme_uonxwgus.png\" data-src=\"https:\/\/habrastorage.org\/webt\/3l\/0d\/sg\/3l0dsgfav4dq7jpvme_uonxwgus.png\"\/><\/div>\n<p><\/a><br \/>  This project is aimed at creating an experimental device for emulating RFID labels of three widely available components. I simplified the explanation of the process so that it could be easily replicated. I also developed some helpful ideas along the way, including writing a special program for converting a serial number into the transmitted data, which will definitely prove useful.<a name=\"habracut\"><\/a><\/p>\n<p>  I already have <a href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/515868\/\">an article (ru)<\/a> about the detailed functionality of EM Marine device. The article contains an exact explanation of how to wind an antenna and how to create an RFID-emulator of three parts. However, although the device itself is simple, its construction is quite difficult. Besides the fact, that not too many people have an oscilloscope, which is necessary to find the correct resonance, you also need a programming tool to flash firmware to an ATtiny85.<\/p>\n<p>  That\u2019s why I decided to make an emulator, that could be replicated by even a kid. All the components are widely available in various stores and you can further extend its functionality according to your ideas. For example, it can store up to several cards and allows attaching a reader, enabling you to store all your cards on one device. However, there are even more of its possibilities, so let\u2019s move on!<\/p>\n<h2><font color=\"#3AC1EF\">Hardware<\/font><\/h2>\n<p>  As I already said, the goal is to create the emulator of the most common and widely available components. Let\u2019s start by exploring its circuit. <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/g0\/cy\/bj\/g0cybjc0um62xwclecsffvtxbao.png\" data-src=\"https:\/\/habrastorage.org\/webt\/g0\/cy\/bj\/g0cybjc0um62xwclecsffvtxbao.png\"\/><\/p>\n<p>  Here we have an oscillatory circuit, which we will shorten at a certain time to change the reader\u2019s current so that it receives the transmitted data. <\/p>\n<p>  The most difficult part here is the oscillatory circuit tuned to a frequency of 125kHz. You can purchase a very cheap RFID-label reader for Arduino named <b>RDM6300<\/b>. Despite its low price, this reader is equipped with an antenna, and its resonance capacitor is already soldered on the board. So, the reader is only needed because of two of its components: a coil and a resonance capacitor. <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/github.com\/dlinyj\/arduino_rfid_emulator\/raw\/master\/img\/0001.jpg\" data-src=\"https:\/\/github.com\/dlinyj\/arduino_rfid_emulator\/raw\/master\/img\/0001.jpg\" data-blurred=\"true\"\/><br \/>  <i><font color=\"#999999\">RDM6300 Reader and its resonance capacitor<\/font><\/i><\/p>\n<p>  I bought this device for a very low price, which in no way correlates with the amount of work needed to tune the antenna up. The most difficult operation is desoldering the capacitor and re-soldering it on a PCB. Though, I believe this task can be accomplished even by a youngster. <\/p>\n<p>  Now we can assemble it all on the PCB. You may wonder why I combine two resistors in parallel. The reason is, that I didn\u2019t have any 10kOm samples at hand and decided to use 20kOm instead. <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ku\/ff\/eq\/kuffeq_sxqk6kftmurdg1amkkte.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ku\/ff\/eq\/kuffeq_sxqk6kftmurdg1amkkte.png\"\/><br \/>  <i><font color=\"#999999\">Assembled emulator<\/font><\/i><\/p>\n<p>  Let&#8217;s have a closer look. I intentionally used a separate little PCB for the capacitor, where it was soldered right on the pins, inserted into the breadboard.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/30\/0o\/he\/300ohewqrwbo81ngvesb7jxpsk8.png\" data-src=\"https:\/\/habrastorage.org\/webt\/30\/0o\/he\/300ohewqrwbo81ngvesb7jxpsk8.png\"\/><\/p>\n<p>  My original intention was to check the operability of the emulator using another RDM6300 (I bought two of these). And I even did that at first, but then decided that it&#8217;s kind of wrong to debug one Arduino using another and purchased an off-the-shelf reader.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/de\/xj\/-t\/dexj-tsc4oldtabjfz4xv6sayus.png\" data-src=\"https:\/\/habrastorage.org\/webt\/de\/xj\/-t\/dexj-tsc4oldtabjfz4xv6sayus.png\"\/><br \/>  <i><font color=\"#999999\">Off-the-shelf reader<\/font><\/i><\/p>\n<h2><font color=\"#3AC1EF\">Programming the timer<\/font><\/h2>\n<p>  Here are a few nuances, which are essential to get an understanding of what I\u2019m doing. <\/p>\n<p>  Remind, that EM4102 uses a Manchester coding scheme, and when the EM4102 protocol is modulated a bit can be transmitted at a rate of 64\/32\/16 carrier cycles (125kHz).<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/yb\/dc\/ki\/ybdckirbutajwtxwyr7ikfnrawg.png\" data-src=\"https:\/\/habrastorage.org\/webt\/yb\/dc\/ki\/ybdckirbutajwtxwyr7ikfnrawg.png\"\/><\/p>\n<p>  Simply put, when a bit is transmitted, either the value of <code>1<\/code> changes to <code>0<\/code> (when transmitting<code>0<\/code>) or the value of <code>0<\/code> changes to <code>1<\/code> (when transmitting <code>1<\/code>). Therefore, if we transmit a bit of information at a rate of 64 carrier cycles, then we use 32 carrier cycles to transmit a \u00abhalf-bit\u00bb. So, every \u00abhalf-bit\u00bb should change with a frequency of:<\/p>\n<pre><code class=\"bash\">f=125000\/32 = 3906,25 Hz<\/code><\/pre>\n<p>  A period of this \u00abhalf-bit\u00bb will last for 256 \u03bcs.<\/p>\n<p>  Now we need to calculate the parameters of the timer, so that it changes the output state with that frequency. But I became so lazy, that after opening a datasheet began to yawn and finally decided to find a ready solution. As it turned out, some timer calculations were readily available and the only thing left was to provide initial data. Meet <a href=\"https:\/\/www.arduinoslovakia.eu\/application\/timer-calculator\">a calculator for Arduino timer<\/a>.<\/p>\n<p>  All you need is to type in the timer frequency, which is 3906Hz, and the program will generate a ready-to-use code. Cool, isn\u2019t it?<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/eu\/o_\/1u\/euo_1uwcs6zj6yknsdbkltkwska.png\" data-src=\"https:\/\/habrastorage.org\/webt\/eu\/o_\/1u\/euo_1uwcs6zj6yknsdbkltkwska.png\"\/><\/p>\n<p>  Note, that I entered the frequency as integers, while the program calculated its fractional representation, which is exactly what we need. As a result, I got the following timer initialization code:<\/p>\n<pre><code class=\"bash\">void setupTimer1() {   noInterrupts();   \/\/ Clear registers   TCCR1A = 0;   TCCR1B = 0;   TCNT1 = 0;    \/\/ 3906.25 Hz (16000000\/((4095+1)*1))   OCR1A = 4095;   \/\/ Prescaler 1   TCCR1B |= (1 &lt;&lt; CS10);   \/\/ Output Compare Match A Interrupt Enable   TIMSK1 |= (1 &lt;&lt; OCIE1A);   interrupts(); }<\/code><\/pre>\n<p>  Brilliant, simple, and concise!<\/p>\n<p>  The output interruption vector also has a simple structure. Remind, that we need to change from <code>1<\/code> to <code>0<\/code> when transmitting<code>0<\/code> and from <code>0<\/code> to <code>1<\/code> when transmitting <code>1<\/code> (see the diagram above). So, we check what is being transmitted and in which part of the \u00abhalf-bit\u00bb we are now, gradually reading all the data from the <code>data <\/code>array. <\/p>\n<pre><code class=\"bash\">ISR(TIMER1_COMPA_vect) {         TCNT1=0; if (((data[byte_counter] &lt;&lt; bit_counter)&amp;0x80)==0x00) {     if (half==0) digitalWrite(ANTENNA, LOW);     if (half==1) digitalWrite(ANTENNA, HIGH); } else {     if (half==0) digitalWrite(ANTENNA, HIGH);     if (half==1) digitalWrite(ANTENNA, LOW); }      half++; if (half==2) {     half=0;     bit_counter++;     if (bit_counter==8) {         bit_counter=0;         byte_counter=(byte_counter+1)%8; } } } <\/code><\/pre>\n<h2><font color=\"#3AC1EF\">Converting data for transmitting<\/font><\/h2>\n<p>  Here, we also need to refresh how the data is stored on the card. Let\u2019s see an actual example.<\/p>\n<p>  Suppose, we have a card but don\u2019t have a reader. There is a number printed on the card: <b>010,48351<\/b>.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/fd\/jf\/yu\/fdjfyu-rieks2pd_px3qbdziyvm.png\" data-src=\"https:\/\/habrastorage.org\/webt\/fd\/jf\/yu\/fdjfyu-rieks2pd_px3qbdziyvm.png\"\/><br \/>  <i><font color=\"#999999\">A real card with the number 010, 48351<\/font><\/i><\/p>\n<p>  How can we translate this number to the ID stored on the card? That\u2019s simple. Recall the formula, which supposes translating two parts of the number separately:<\/p>\n<pre><code class=\"bash\">010d = 0xA 48351d = 0xBCDF<\/code><\/pre>\n<p>  As a result, we get our serial number as <code>0xABCDF<\/code>. Let\u2019s check it by scanning the card with the reader. We get a decimal number: <\/p>\n<pre><code class=\"bash\">0000703711<\/code><\/pre>\n<p>  Then, we convert it to a hex-string and here is that number again: <code>0xABCDF<\/code>.<\/p>\n<p>  It seems quite simple, but there is a complex part ahead. I\u2019ll remind you of the format in which the data is stored on the card. <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/gy\/m2\/e_\/gym2e_ltulsf_v4g7pjhdxd0gi0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/gy\/m2\/e_\/gym2e_ltulsf_v4g7pjhdxd0gi0.png\"\/><\/p>\n<p>  Detailed explanation:<\/p>\n<ol>\n<li>First, there are nine ones in the header.<\/li>\n<li>The lower nibble of the client\u2019s ID<\/li>\n<li>A parity bit in the end.<\/li>\n<li>The second nibble of the client\u2019s ID.<\/li>\n<li>A parity bit.<\/li>\n<li>The lower nibble of the zero byte of the serial number.<\/li>\n<li>A parity bit.<\/li>\n<li>The upper nibble of the zero byte of the serial number.<\/li>\n<li>The rest of the data is transmitted the same way through nibbles with a parity bit in the end.<\/li>\n<li>The most difficult part. The parity bits are calculated for all 10 nibbles.<\/li>\n<li>Finally, all this beastliness ends with a stop bit, which is always <code>0<\/code>.<\/li>\n<\/ol>\n<p>  As a result, we get 64 bits of data (from 5 bytes!). Here, I should mention that my reader doesn\u2019t read the client\u2019s ID, so I take it as 0.<\/p>\n<p>  What is a parity bit? A parity bit is used to check for errors during transmitting. To know its value we calculate the number of ones in the transmitted data. if it&#8217;s even, then the bit is <code>0<\/code>, and if it\u2019s not, then the bit is <code>1<\/code>. XOR is the easiest way to calculate it. <\/p>\n<p>  I spent much time thinking of how to elegantly convert the serial number to the transmitted data so that it also would take less memory of the MCU. Finally, I sketched a small program that does just that. The program can be found under the spoiler below.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Program for testing conversion of a serial number into transmitted data<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">#include &lt;stdio.h> #include &lt;stdlib.h> #include &lt;stdint.h>  #define BYTE_TO_BINARY_PATTERN \"%c%c%c%c%c%c%c%c\" #define BYTE_TO_BINARY(byte)  \\   (byte &amp; 0x80 ? '1' : '0'), \\   (byte &amp; 0x40 ? '1' : '0'), \\   (byte &amp; 0x20 ? '1' : '0'), \\   (byte &amp; 0x10 ? '1' : '0'), \\   (byte &amp; 0x08 ? '1' : '0'), \\   (byte &amp; 0x04 ? '1' : '0'), \\   (byte &amp; 0x02 ? '1' : '0'), \\   (byte &amp; 0x01 ? '1' : '0')   #define NYBBLE_TO_BINARY_PATTERN \"%c%c%c%c\" #define NYBBLE_TO_BINARY(byte)  \\ (byte &amp; 0x08 ? '1' : '0'), \\ (byte &amp; 0x04 ? '1' : '0'), \\ (byte &amp; 0x02 ? '1' : '0'), \\ (byte &amp; 0x01 ? '1' : '0')    int main() { \/\/unsigned long long card_id = 0x00000ABCDF; \/\/uint64_t card_id = 0x00000ABCDF; uint64_t card_id = (uint64_t)3604000; uint64_t data_card_ul = 0x1FFF; \/\/first 9 bit as 1 int32_t i; uint8_t tmp_nybble; uint8_t column_parity_bits = 0; printf(\"card_id = 0x%lX\\n\", card_id); for (i = 9; i >= 0; i--) { \/\/5 bytes = 10 nybbles tmp_nybble = (uint8_t) (0x0f &amp; (card_id >> i*4)); data_card_ul = (data_card_ul &lt;&lt; 4) | tmp_nybble; printf(\"0x%02X\", (int) tmp_nybble); printf(\"\\t\"NYBBLE_TO_BINARY_PATTERN, NYBBLE_TO_BINARY(tmp_nybble)); printf(\"\\t %d\\n\", (tmp_nybble >> 3 &amp; 0x01) ^ (tmp_nybble >> 2 &amp; 0x01) ^\\ (tmp_nybble >> 1 &amp; 0x01) ^ (tmp_nybble  &amp; 0x01)); data_card_ul = (data_card_ul &lt;&lt; 1) | ((tmp_nybble >> 3 &amp; 0x01) ^ (tmp_nybble >> 2 &amp; 0x01) ^\\ (tmp_nybble >> 1 &amp; 0x01) ^ (tmp_nybble  &amp; 0x01)); column_parity_bits ^= tmp_nybble; } data_card_ul = (data_card_ul &lt;&lt; 4) | column_parity_bits; data_card_ul = (data_card_ul &lt;&lt; 1); \/\/1 stop bit = 0 printf(\"\\t\"NYBBLE_TO_BINARY_PATTERN\"\\n\", NYBBLE_TO_BINARY(column_parity_bits)); printf(\"data_card_ul = 0x%lX\\n\", data_card_ul);  for (i = 7; i >= 0; i--) { printf(\"0x%02X,\", (int) (0xFF &amp; (data_card_ul >> i * 8))); } printf(\"\\n\"); return 0; }<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  Most of all, we are interested in the parity bits. For convenience, I made the output on the screen look the same as in the table. Here is the result.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/1x\/cy\/u1\/1xcyu1acqo5ssgqyybfvdqnvvgu.png\" data-src=\"https:\/\/habrastorage.org\/webt\/1x\/cy\/u1\/1xcyu1acqo5ssgqyybfvdqnvvgu.png\"\/><\/p>\n<p>  <code>card_id<\/code> \u2014 is the card\u2019s serial number (which was mentioned above).<\/p>\n<p>  The first column holds nibbles, the second one shows their bit representation and the third column represents the parity bit. The third row from the bottom contains the parity bits of all the nibbles. As I already said, they&#8217;re calculated with XOR.<\/p>\n<p>  After testing all the calculations and matching them visually I checked the resulting data in an Arduino program (the last row from the picture should be inserted in code). All had worked just fine. Thanks to the sketched program, now I can easily convert any serial number to the transmitted data. Earlier, the bit calculations were carried out by individual programs on my PC and I didn&#8217;t like such a cumbersome process. That said, the function for translating a serial number into the transmitted format looks as follows:<\/p>\n<pre><code class=\"bash\">#define CARD_ID 0xABCDF  uint8_t data[8];  void data_card_ul() {   uint64_t card_id = (uint64_t)CARD_ID;   uint64_t data_card_ul = (uint64_t)0x1FFF; \/\/first 9 bit as 1   int32_t i;   uint8_t tmp_nybble;   uint8_t column_parity_bits = 0;   for (i = 9; i >= 0; i--) { \/\/5 bytes = 10 nibbles     tmp_nybble = (uint8_t) (0x0f &amp; (card_id >> i*4));     data_card_ul = (data_card_ul &lt;&lt; 4) | tmp_nybble;     data_card_ul = (data_card_ul &lt;&lt; 1) | ((tmp_nybble >> 3 &amp; 0x01) ^ (tmp_nybble >> 2 &amp; 0x01) ^\\       (tmp_nybble >> 1 &amp; 0x01) ^ (tmp_nybble  &amp; 0x01));     column_parity_bits ^= tmp_nybble;   }   data_card_ul = (data_card_ul &lt;&lt; 4) | column_parity_bits;   data_card_ul = (data_card_ul &lt;&lt; 1); \/\/1 stop bit = 0   for (i = 0; i &lt; 8; i++) {     data[i] = (uint8_t)(0xFF &amp; (data_card_ul >> (7 - i) * 8));   } }<\/code><\/pre>\n<p>  That\u2019s it! Time for testing a real scenario. The project\u2019s source code can be found here.<\/p>\n<h2><font color=\"#3AC1EF\">Test run<\/font><\/h2>\n<p>  It is better to see something once than to read about it a thousand times as they speak. I also decided to record a demonstration of the working emulator. I had an idea to test it with real hardware and tried to sneak inside our company\u2019s office building with the help of Arduino, but due to the damn pandemic restrictions, no one is allowed in. That\u2019s why I had to run a full-scale test on my lab table. <\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/5fda8e143b295d140fdb3920\" data-style=\"\" id=\"5fda8e143b295d140fdb3920\" width=\"\"><\/div>\n<\/div>\n<p>  <\/p>\n<h2><font color=\"#3AC1EF\">Conclusion<\/font><\/h2>\n<p>  I do hope that such kinds of articles will encourage neophytes to master programming and electronics. Besides, it would be good if this information facilitated the removal of such unprotected and unsafe cards from the market, as now they can be easily cloned and emulated by even a kid.<\/p>\n<h2><font color=\"#3AC1EF\">Resources<\/font><\/h2>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dlinyj\/arduino_rfid_emulator\">The source code<\/a><\/li>\n<li><a href=\"https:\/\/d1.amobbs.com\/bbs_upload782111\/files_17\/ourdev_469025.pdf\">Unique (EM4001) RFID Emulator<\/a><\/li>\n<\/ul>\n<p>  <a href=\"http:\/\/ruvds.com\/ru-rub?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=dlinyj&amp;utm_content=emulyator_rfid_na_arduino#order\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ou\/g5\/kh\/oug5kh6sjydt9llengsiebnp40w.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ou\/g5\/kh\/oug5kh6sjydt9llengsiebnp40w.png\"\/><\/a><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/570114\/\"> https:\/\/habr.com\/ru\/articles\/570114\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><a href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/570114\/\"><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/3l\/0d\/sg\/3l0dsgfav4dq7jpvme_uonxwgus.png\" data-src=\"https:\/\/habrastorage.org\/webt\/3l\/0d\/sg\/3l0dsgfav4dq7jpvme_uonxwgus.png\"\/><\/div>\n<p><\/a><br \/>  This project is aimed at creating an experimental device for emulating RFID labels of three widely available components. I simplified the explanation of the process so that it could be easily replicated. I also developed some helpful ideas along the way, including writing a special program for converting a serial number into the transmitted data, which will definitely prove useful.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-410002","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410002","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=410002"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410002\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=410002"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=410002"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=410002"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}