Dashlt is an Android application which the user can use to create verifiable video evidence using decentralized trusted timestamping. This way in case of an accident or collision, if the application recorded the event, the video can be used as valid evidence to prove the fact and it can be accepted by the Juridicial System or an insurance company. In case of an accident/collision the video will be recorded and a hash will be generated and sent to the ‘Originstamp’ for timestamping and the user can use the video as verifiable evidence.
Most present technologies which record accidents cannot be used as legal proof because of the methods used in recording and also because they cannot prove an exact time of accident. The videos provided by Dash Cams can be modified and the metadata such as time and date can also be altered by the user, making them not a valid proof in case of an event. Another problem which occurs is that trusted timestamping methods are not easily accessible because of costs and they can also be tampered with.
1. Intel Edison + GoPro (WebCam, Kinect) + Sensors (Accelerometer, GPS, Gyroscope)
• Intel Edison – For sending video over internet in case of accident • GoPro – To record the video • Sensors – To detect accident/collision
2. Smartphone
• Smartphone sensors to detect accident/collision • Smartphone camera to record the video • Mobile Data to connect to internet
During the workshop session multiple design solutions were proposed like PhoneGap or Cordova, but due to hardware and software limitations we switched to Android which can access all the features of a phone that are needed by the application and offers the possibility to run an application in the background. For hashing the video we used OriginStamp.org as the trusted timestamping method.
The application can be used by any person that owns an Android device with internet connection to access the application and send the hash of the evidence video, a camera that records the accident and an accelerometer which uses sensors to detect the movement in case of collision. A video will be recorded at every certain point in time and only the important length of the video will be hashed and sent for timestamping. In this case the user will be notified about the process and he will be able to access his events in a history panel along with verification details, so he can use the system for legal purposes.
The user turns on the application and starts recording then locks the application in Task Manager and the phone does the rest of the work. When an accident/collision occurs, the video is hashed and sent to OriginStamp and the user receives the confirmation of the timestamping. In the History Screen the user can see his accident(s) /collision(s) history with date, time and hashing value so that he can use it in Judicial Systems.
• Week 1:
o Design system and choose technologies
• Week 2:
o Iterating the design for improvements, finalizing the design
• Week 3:
o System Implementation
• Week 4:
o System Implementation
• Week 5:
o System Implementation
• Week 6:
o Testing the system o Presentation, Wiki Article, Demo Video
OriginStamp is a non-commercial free of charge trusted timestamping REST API that can be used to prove that a person was the originator of a piece of information at a certain point in time. The advantage of OriginStamp compared to other trusted timestamping methods is that it is free of charge and allows the user to create anonymous timestamps in a secure and valid manner that uses the cryptographic blockchain of virtual bitcoins.
OriginStamp is called by a HTTP request to the API. For the API to authorize access a parameter Token token=„{YOUR_API_KEY}“ needs to be provided in the Authorization field.
Example request:
POST http://www.originstamp.org/api/stamps Authorization: Token token="{YOUR_API_KEY}" Content-Type: application/json { "hash_sha256" : "6b4a1673b225e8bf5f093b91be8c864427df32ca41b17cc0b82112b8f0185e41" }
Generate Hash:
public void generateHash(){ int[] orderOfVideo = new int[3]; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); if(accidentOnVideoIndex == 2){ orderOfVideo[0] = 1; orderOfVideo[1] = 2; orderOfVideo[2] = 3; }else{ orderOfVideo[0] = 2; orderOfVideo[1] = 1; orderOfVideo[2] = 3; } for(int i=0;i<3;i++){ File file = new File("/sdcard/dashit"+orderOfVideo[i]+".mp4"); if(file.exists() && !file.isDirectory()){ byte[] byteArray = new byte[(int)file.length()]; FileInputStream fileInputStream; try { fileInputStream = new FileInputStream(file); fileInputStream.read(byteArray); System.out.println("File length::"+byteArray.length); outputStream.write(byteArray); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } byte[] finalByte = outputStream.toByteArray(); try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(finalByte); byte[] mdBytes = md.digest(); StringBuffer hexString = new StringBuffer(); for (int i=0;i<mdBytes.length;i++) { hexString.append(Integer.toHexString(0xFF & mdBytes[i])); } System.out.println("Hex format : " + hexString.toString()); sendHashToServer(hexString.toString()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }
Send hash to server:
public void sendHashToServer(String hashString){ String url = "http://www.originstamp.org/api/stamps"; String postData = "{\"hash_sha256\" : \""+hashString+"\"}"; try { URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/json"); con.setRequestProperty("Authorization", "Token token=\"a876e0bbb8894e8c8eadc5b3a19adff7\""); con.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) "); con.setRequestProperty("Accept","*/*"); DataOutputStream dos = new DataOutputStream(con.getOutputStream()); dos.writeBytes(postData); dos.flush(); dos.close(); String line; BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream())); while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { System.out.println("Accident!!"); accidentStatus = true; } } }
Accelerometer (Sensors) access:
public class SensorService extends Service implements SensorEventListener { private SensorManager manager = null; private Sensor sensor = null; private long lastUpdate = 0; private float last_x, last_y, last_z; ResultReceiver resultReceiver; public int onStartCommand(Intent intent, int flags, int startId){ resultReceiver = intent.getParcelableExtra("receiver"); manager = (SensorManager)getSystemService(SENSOR_SERVICE); sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); boolean sensorAvailable = manager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST); if(sensorAvailable){ System.out.println("Sensor available"); }else{ System.out.println("Some problem when retrieving the sensor."); } return START_STICKY; } @Override public void onSensorChanged(SensorEvent event) { float x = event.values[0]; float y = event.values[1]; float z = event.values[2]; long curTime = System.currentTimeMillis(); if ((curTime - lastUpdate) > 100) { long diffTime = (curTime - lastUpdate); lastUpdate = curTime; float speed = Math.abs(x + y + z - last_x - last_y - last_z)/ diffTime * 10000; if(Math.abs(x-last_x) > 8 || Math.abs(y-last_y) > 8 || Math.abs(z-last_z) > 8){ Bundle bundle = new Bundle(); bundle.putString("state","Accident!!!"); resultReceiver.send(100,bundle); Intent intent = new Intent(); intent.setAction("com.example.Broadcast"); intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); sendBroadcast(intent); }else{ Bundle bundle = new Bundle(); bundle.putString("state","You are good!!!"); resultReceiver.send(100,bundle); } last_x = x; last_y = y; last_z = z; } new SensorEventLoggerTask().execute(event); stopSelf(); @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Nullable @Override public IBinder onBind(Intent intent) { return null; } public class SensorEventLoggerTask extends AsyncTask<SensorEvent, Void, Void> { @Override public Void doInBackground(SensorEvent... events) { for(int i=0;i<events.length;i++){ SensorEvent event = events[i]; for(int j=0;j<event.values.length;j++){ //System.out.println("Sensor Data::"+event.values[i]); } } return null; } } }
Video recording:
public boolean startRecording(String fileName){ try { //Toast.makeText(getBaseContext(), "Recording Started", Toast.LENGTH_SHORT).show(); mRecordingStatus = true; mServiceCamera = Camera.open(); Camera.Parameters params = mServiceCamera.getParameters(); mServiceCamera.setParameters(params); Camera.Parameters p = mServiceCamera.getParameters(); final List<Camera.Size> listSize = p.getSupportedPreviewSizes(); Camera.Size mPreviewSize = listSize.get(2); Log.v(TAG, "use: width = " + mPreviewSize.width + " height = " + mPreviewSize.height); p.setPreviewSize(mPreviewSize.width, mPreviewSize.height); p.setPreviewFormat(PixelFormat.YCbCr_420_SP); mServiceCamera.setParameters(p); mServiceCamera.setDisplayOrientation(90); try { mServiceCamera.setPreviewDisplay(mSurfaceHolder); mServiceCamera.startPreview(); } catch (IOException e) { Log.e(TAG, e.getMessage()); e.printStackTrace(); } mServiceCamera.unlock(); mMediaRecorder = new MediaRecorder(); mMediaRecorder.setCamera(mServiceCamera); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P)); //mMediaRecorder.setMaxDuration(10000); mMediaRecorder.setOutputFile("/sdcard/" + fileName + ".mp4"); mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); mMediaRecorder.prepare(); mMediaRecorder.start(); return true; } catch (IllegalStateException e) { Log.d(TAG, e.getMessage()); e.printStackTrace(); return false; } catch (IOException e) { Log.d(TAG, e.getMessage()); e.printStackTrace(); return false; } }