Felicaに書き込む練習

#書き込めるFelica
ICカードの規格であるFelicaには、Suica,PASMOのような交通系カードやnanacoやWAONのような流通系カードなどいろいろあります。それぞれのカードでフォーマットが異なりますが、ほとんどのカードは鍵付きで書き込む仕様になっており、nfcpyなどで暗号なしで書き込むAPIであるwrite_without_encryptionがあるのですが試してみることができせん。一般人の入手できるカードの中でも暗号なしで書き込めるカードがPASMOです。PASMOにはsuicaと同じ0x0003番のプライベート領域に加えて、Suicaにはないシステムシステムコード0xFE00番の共通領域があります。その中に、サービスコード0x39C9があり、６ブロックですが write w/o key 属性を持っています。

```
  System FE00 (Common Area)
  Area 0000--FFFE
    Area 3940--39FF
      Area 3941--39FF
        Random Service 229: write with key & read w/o key (0x3948 0x394B)
         0000: f9 49 db c2 08 00 00 f1 01 00 00 00 00 00 00 00 |.I..............|
        Random Service 230: write with key & read w/o key (0x3988 0x398B)
         0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         000F: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
        Random Service 231: write w/o key (0x39C9)
         0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
```
上記ダンプを出力するnfcpyを使ったコードはいろいろなところで見かけますが、２０行足らずで誰が書いても同じになるでしょうから、出典を記さず貼り付けておきます。

```python
import nfc 

def on_connect(tag):
  print(tag)
  # タグのIDなどを出力する
  if isinstance(tag, nfc.tag.tt3.Type3Tag):
    try:
      # 内容を16進数で出力する
     print('  ' + '\n  '.join(tag.dump()))
    except Exception as e:
     print("error: %s" % e)
  else:
    print( "error: tag isn't Type3Tag")

def main():
  with nfc.ContactlessFrontend('usb') as clf:
    clf.connect(rdwr={'on-connect': on_connect})

if __name__ == '__main__':
  main()
```
#PASMOに書き込んでみる
0x39C9の2ブロック目に何らかのデータを書き込んでみます。

```python
import nfc 
import binascii
import time
import logging

syscode=0xFE00
svccode=0x39C9
logging.basicConfig()
#logging.getLogger('nfc').setLevel(logging.DEBUG-1)

def on_connect(tag):
  print ("on connect")
  print (str(tag))
  if isinstance(tag,nfc.tag.tt3.Type3Tag):
    tag.idm,tag.pmm=tag.polling(system_code=syscode)
    tag.sys=syscode
    try:
      sc=nfc.tag.tt3.ServiceCode(svccode>>6,svccode&0x3F)
      bc=nfc.tag.tt3.BlockCode(2)
      data=tag.write_without_encryption([sc],[bc],bytearray(b"(c) Hiroaki Hata"))
      print("wrote")
    except Exception as e:
      print("exception:%s" % e)
  else:
    print("not Type3Tag")
  return True 

def main():
  print('start')
  with nfc.ContactlessFrontend('usb') as clf:
    clf.connect(rdwr={'on-connect':on_connect})

if __name__=='__main__':
  main()
```
write_without_encryptionの第３パラメータに16バイト分のデータアレイを指定します。0クリアしたければbytearray(16)で置き換えます。データシーケンスが見たければ、logging.getLogger('nfc').setLevel(logging.DEBUG-1)のコメントを外してください。

これを一回動作させたあとで、もう一度DUMPしてみます。

```
System FE00 (Common Area)
  Area 0000--FFFE
    Area 3940--39FF
      Area 3941--39FF
        Random Service 229: write with key & read w/o key (0x3948 0x394B)
         0000: f9 49 db c2 08 00 00 f1 01 00 00 00 00 00 00 00 |.I..............|
        Random Service 230: write with key & read w/o key (0x3988 0x398B)
         0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         000F: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
        Random Service 231: write w/o key (0x39C9)
         0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         0002: 28 63 29 20 48 69 72 6f 61 6b 69 20 48 61 74 61 |(c) Hiroaki Hata|
         0003: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

```